OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
traceroute.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include <stdint.h>
6 #include <netinet/udp.h>
7 #include <netinet/tcp.h>
8 #include <netinet/icmp6.h>
9 #include "vr_defs.h"
10 #include "cmn/agent_cmn.h"
11 #include "oper/nexthop.h"
12 #include "oper/route_common.h"
13 #include "oper/mirror_table.h"
14 #include "pkt/proto.h"
15 #include "pkt/proto_handler.h"
16 #include "diag/diag_types.h"
17 #include "diag/diag_pkt_handler.h"
18 #include "diag/diag.h"
19 #include "diag/traceroute.h"
20 
21 void
22 TraceRoute::SendSandeshReply(const std::string &address,
23  const std::string &context,
24  bool more) {
25  TraceRouteResp *resp = new TraceRouteResp();
26  resp->set_hop(address);
27 
28  resp->set_context(context);
29  resp->set_more(more);
30  resp->Response();
31 }
32 
33 TraceRoute::TraceRoute(const TraceRouteReq *trace_route_req,
34  DiagTable *diag_table) :
35  DiagEntry(trace_route_req->get_source_ip(), trace_route_req->get_dest_ip(),
36  trace_route_req->get_protocol(), trace_route_req->get_source_port(),
37  trace_route_req->get_dest_port(), trace_route_req->get_vrf_name(),
38  trace_route_req->get_interval() * 100,
39  trace_route_req->get_max_attempts(), diag_table),
40  done_(false), ttl_(2),
41  max_ttl_(trace_route_req->get_max_hops()),
42  context_(trace_route_req->context()) {
43 }
44 
46 }
47 
49  data->op_ = htonl(AgentDiagPktData::DIAG_REQUEST);
50  data->key_ = htons(key_);
51  data->seq_no_ = htonl(seq_no_);
52  memset(data->data_, 0, sizeof(data->data_));
53  // data->rtt_ = microsec_clock::universal_time();
54 }
55 
57  Agent *agent = diag_table_->agent();
58 
60  if (sip_.is_v4()) {
62  } else {
64  }
65  AgentRoute *rt = table->FindRoute(sip_);
66  if (!rt) return;
67 
68  const NextHop *nh = rt->GetActiveNextHop();
69  if (!nh || nh->GetType() != NextHop::INTERFACE) return;
70 
71  const InterfaceNH *intf_nh;
72  intf_nh = static_cast<const InterfaceNH *>(nh);
73 
74  uint32_t intf_id = intf_nh->GetInterface()->id();
75  uint32_t vrf_id = agent->vrf_table()->FindVrfFromName(vrf_name_)->vrf_id();
76 
77  //Allocate buffer to hold packet
78  boost::shared_ptr<PktInfo> pkt_info(new PktInfo(agent, kBufferSize,
79  PktHandler::DIAG, 0));
80  uint8_t *msg = pkt_info->packet_buffer()->data();
81  memset(msg, 0, kBufferSize);
82 
83  DiagPktHandler *pkt_handler =
84  new DiagPktHandler(agent, pkt_info,
85  *(agent->event_manager())->io_service());
86  uint16_t len = sizeof(AgentDiagPktData);
87  uint8_t *data = NULL;
88  if (sip_.is_v4()) {
89  //Update pointers to ethernet header, ip header and l4 header
90  pkt_info->UpdateHeaderPtr();
91  switch (proto_) {
92  case IPPROTO_TCP:
93  len += sizeof(tcphdr);
94  data = (uint8_t *)pkt_handler->pkt_info()->transp.tcp + sizeof(tcphdr);
95  pkt_handler->TcpHdr(htonl(sip_.to_v4().to_ulong()), sport_,
96  htonl(dip_.to_v4().to_ulong()), dport_,
97  false, rand(), len);
98  pkt_handler->pkt_info()->transp.tcp->check = 0xffff;
99  break;
100 
101  case IPPROTO_UDP:
102  len += sizeof(udphdr);
103  data = (uint8_t *)pkt_handler->pkt_info()->transp.udp + sizeof(udphdr);
104  pkt_handler->UdpHdr(len, sip_.to_v4().to_ulong(), sport_,
105  dip_.to_v4().to_ulong(), dport_);
106  pkt_handler->pkt_info()->transp.udp->check = 0xffff;
107  break;
108 
109  case IPPROTO_ICMP:
110  len += 8;
111  data = (uint8_t *)pkt_handler->pkt_info()->transp.icmp + 8;
112  pkt_handler->pkt_info()->transp.icmp->icmp_type = ICMP_ECHO;
113  pkt_handler->pkt_info()->transp.icmp->icmp_code = 0;
114  pkt_handler->pkt_info()->transp.icmp->icmp_cksum = 0xffff;
115  break;
116  }
117  FillHeader((AgentDiagPktData *)data);
118  len += sizeof(struct ip);
119  pkt_handler->IpHdr(len, ntohl(sip_.to_v4().to_ulong()),
120  ntohl(dip_.to_v4().to_ulong()),
121  proto_, key_, ttl_);
122  len += sizeof(ether_header);
123  pkt_handler->EthHdr(agent->vhost_interface()->mac(),
124  agent->vrrp_mac(), ETHERTYPE_IP);
125  } else {
126  pkt_info->eth = (struct ether_header *)(pkt_handler->pkt_info()->pkt);
127  pkt_info->ip6 = (struct ip6_hdr *)(pkt_info->eth + 1);
128  switch (proto_) {
129  case IPPROTO_TCP:
130  pkt_info->transp.tcp = (struct tcphdr *)(pkt_info->ip6 + 1);
131  len += sizeof(tcphdr);
132  data = (uint8_t *)pkt_handler->pkt_info()->transp.tcp + sizeof(tcphdr);
133  pkt_handler->TcpHdr(len+sizeof(tcphdr),
134  sip_.to_v6().to_bytes().data(), sport_,
135  dip_.to_v6().to_bytes().data(), dport_,
136  false, rand(), IPPROTO_TCP);
137  pkt_handler->pkt_info()->transp.tcp->check = 0xffff;
138  break;
139 
140  case IPPROTO_UDP:
141  pkt_info->transp.udp = (struct udphdr *)(pkt_info->ip6 + 1);
142  len += sizeof(udphdr);
143  data = (uint8_t *)pkt_handler->pkt_info()->transp.udp + sizeof(udphdr);
144  pkt_handler->UdpHdr(len + sizeof(udphdr),
145  sip_.to_v6().to_bytes().data(), sport_,
146  dip_.to_v6().to_bytes().data(), dport_,
147  IPPROTO_UDP);
148  pkt_handler->pkt_info()->transp.udp->check = 0xffff;
149  break;
150 
151  case IPPROTO_ICMPV6:
152  len += 8;
153  data = (uint8_t *)pkt_handler->pkt_info()->transp.icmp + 8;
154  pkt_handler->pkt_info()->transp.icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
155  pkt_handler->pkt_info()->transp.icmp6->icmp6_code = 0;
156  pkt_handler->pkt_info()->transp.icmp6->icmp6_cksum = 0xffff;
157  break;
158  }
159  FillHeader((AgentDiagPktData *)data);
160  len += sizeof(struct ip6_hdr);
161  pkt_handler->Ip6Hdr(pkt_info->ip6,
162  len + sizeof(udphdr) + sizeof(struct ip6_hdr),
163  IPPROTO_UDP, ttl_, sip_.to_v6().to_bytes().data(),
164  dip_.to_v6().to_bytes().data());
165  len += sizeof(ether_header);
166  pkt_handler->EthHdr(agent->vhost_interface()->mac(),
167  agent->vrrp_mac(), ETHERTYPE_IPV6);
168  }
169  //Increment the attempt count
170  seq_no_++;
171 
172  //Send request out
173  pkt_handler->pkt_info()->set_len(len);
174  pkt_handler->Send(intf_id, vrf_id, AgentHdr::TX_ROUTE,
175  CMD_PARAM_PACKET_CTRL, CMD_PARAM_1_DIAG, PktHandler::DIAG);
176  delete pkt_handler;
177  return;
178 }
179 
180 // if timed out max times for a TTL, reply and increment ttl
181 void TraceRoute::RequestTimedOut(uint32_t seqno) {
182  if (seq_no_ >= GetMaxAttempts()) {
183  std::string address;
184  for (uint32_t i = 0; i < GetMaxAttempts(); i++)
185  address += "* ";
186 
187  done_ = ((ttl_ >= max_ttl_) ? true : false);
188  SendSandeshReply(address, context_, !done_);
189  IncrementTtl();
190  }
191 }
192 
193 // Ready to send a response and increment ttl
195  if (ttl_ >= max_ttl_) {
196  handler->set_done(true);
197  done_ = true;
198  }
199  SendSandeshReply(handler->GetAddress(), context_, !handler->IsDone());
200  IncrementTtl();
201 }
202 
203 // Reply with local node as the first hop
205  SendSandeshReply(diag_table_->agent()->router_id().to_string(),
206  context_, true);
207 }
208 
210 }
211 
213  return done_;
214 }
215 
217  ttl_++;
218  seq_no_ = 0;
219 }
220 
221 void TraceRouteReq::HandleRequest() const {
222  std::string err_str;
223  boost::system::error_code ec;
224  TraceRoute *trace_route = NULL;
225 
226  {
227  IpAddress sip(IpAddress::from_string(get_source_ip(), ec));
228  if (ec.failed()) {
229  err_str = "Invalid source IP";
230  goto error;
231  }
232 
233  IpAddress dip(IpAddress::from_string(get_dest_ip(), ec));
234  if (ec.failed()) {
235  err_str = "Invalid destination IP";
236  goto error;
237  }
238 
239  uint8_t proto = get_protocol();
240  if (proto != IPPROTO_TCP && proto != IPPROTO_UDP && proto != IPPROTO_ICMP) {
241  err_str = "Invalid protocol - Supported protocols are TCP, UDP and ICMP";
242  goto error;
243  }
244 
245  if (Agent::GetInstance()->vrf_table()->FindVrfFromName(get_vrf_name()) == NULL) {
246  err_str = "Invalid VRF";
247  goto error;
248  }
249 
250  const NextHop *nh = NULL;
251  Agent *agent = Agent::GetInstance();
253  if (sip.is_v4()) {
254  table = agent->vrf_table()->GetInet4UnicastRouteTable(get_vrf_name());
255  } else {
256  table = agent->vrf_table()->GetInet6UnicastRouteTable(get_vrf_name());
257  }
258  AgentRoute *rt = table->FindRoute(sip);
259  if (rt) {
260  nh = rt->GetActiveNextHop();
261  }
262  if (!nh || nh->GetType() != NextHop::INTERFACE) {
263  err_str = "Source VM is not present in this server";
264  goto error;
265  }
266 
267  rt = table->FindRoute(dip);
268  if (rt) {
269  nh = rt->GetActiveNextHop();
270  if (nh && nh->GetType() == NextHop::INTERFACE) {
271  // Dest VM is also local
272  TraceRoute::SendSandeshReply(agent->router_id().to_string(),
273  context(), false);
274  return;
275  }
276  }
277  }
278 
279  trace_route = new TraceRoute(this, Agent::GetInstance()->diag_table());
280  trace_route->ReplyLocalHop();
281  trace_route->Init();
282  return;
283 
284 error:
285  TraceRouteErrResp *resp = new TraceRouteErrResp;
286  resp->set_error_response(err_str);
287  resp->set_context(context());
288  resp->Response();
289  return;
290 }
IpAddress dip_
Definition: diag.h:57
std::string context_
Definition: traceroute.h:38
const Interface * GetInterface() const
Definition: nexthop.h:1293
IpAddress sip_
Definition: diag.h:56
uint32_t GetMaxAttempts()
Definition: diag.h:42
static Agent * GetInstance()
Definition: agent.h:436
union PktInfo::@8 transp
virtual void HandleReply(DiagPktHandler *handler)
Definition: traceroute.cc:194
VrfEntry * FindVrfFromName(const string &name)
Definition: vrf.cc:873
const uint32_t id() const
Definition: interface.h:123
void set_done(bool done)
void IncrementTtl()
Definition: traceroute.cc:216
const Interface * vhost_interface() const
Definition: agent.h:935
uint8_t proto_
Definition: diag.h:58
boost::asio::ip::address IpAddress
Definition: address.h:13
static const MacAddress & vrrp_mac()
Definition: agent.h:439
uint32_t seq_no_
Definition: diag.h:84
void set_len(uint32_t len)
uint32_t op_
Definition: diag.h:82
void SendSummary()
Definition: traceroute.cc:209
char data_[8]
Definition: diag.h:85
static const int kBufferSize
Definition: traceroute.h:15
InetUnicastRouteEntry * FindRoute(const IpAddress &ip)
const MacAddress & mac() const
Definition: interface.h:131
struct icmp6_hdr * icmp6
Definition: pkt_handler.h:429
uint16_t dport_
Definition: diag.h:60
Type GetType() const
Definition: nexthop.h:405
Base class for all Route entries in agent.
Definition: agent_route.h:224
TraceRoute(const TraceRouteReq *req, DiagTable *diag_table)
Definition: traceroute.cc:33
InetUnicastAgentRouteTable * GetInet4UnicastRouteTable(const std::string &vrf_name)
Definition: vrf.cc:898
void RequestTimedOut(uint32_t seqno)
Definition: traceroute.cc:181
int EthHdr(const MacAddress &src, const MacAddress &dest, const uint16_t proto)
void Init()
Definition: diag.cc:47
Definition: agent.h:358
virtual void SendRequest()
Definition: traceroute.cc:56
void ReplyLocalHop()
Definition: traceroute.cc:204
struct udphdr * udp
Definition: pkt_handler.h:427
const NextHop * GetActiveNextHop() const
Definition: agent_route.cc:881
Ip4Address router_id() const
Definition: agent.h:666
uint8_t * pkt
Definition: pkt_handler.h:379
EventManager * event_manager() const
Definition: agent.h:1103
uint16_t max_ttl_
Definition: traceroute.h:37
void Send(uint32_t itf, uint32_t vrf, uint16_t, PktHandler::PktModuleName)
DiagEntry::DiagKey key_
Definition: diag.h:83
uint32_t seq_no_
Definition: diag.h:70
Agent * agent() const
Definition: diag.h:117
PktInfo * pkt_info() const
Definition: proto_handler.h:88
const uint32_t vrf_id() const
Definition: vrf.h:99
void TcpHdr(in_addr_t, uint16_t, in_addr_t, uint16_t, bool, uint32_t, uint16_t)
virtual ~TraceRoute()
Definition: traceroute.cc:45
std::string vrf_name_
Definition: diag.h:61
void Ip6Hdr(ip6_hdr *ip, uint16_t plen, uint8_t next_header, uint8_t hlim, uint8_t *src, uint8_t *dest)
VrfTable * vrf_table() const
Definition: agent.h:485
virtual bool IsDone()
Definition: traceroute.cc:212
uint16_t sport_
Definition: diag.h:59
uint8_t ttl_
Definition: traceroute.h:36
bool done_
Definition: traceroute.h:35
struct tcphdr * tcp
Definition: pkt_handler.h:426
void UdpHdr(uint16_t len, in_addr_t src, uint16_t src_port, in_addr_t dest, uint16_t dest_port)
static void SendSandeshReply(const std::string &address, const std::string &context, bool more)
Definition: traceroute.cc:22
struct icmp * icmp
Definition: pkt_handler.h:428
bool IsDone() const
Definition: diag.h:21
InetUnicastAgentRouteTable * GetInet6UnicastRouteTable(const std::string &vrf_name)
Definition: vrf.cc:922
DiagKey key_
Definition: diag.h:65
const std::string & GetAddress() const
void FillHeader(AgentDiagPktData *data)
Definition: traceroute.cc:48
DiagTable * diag_table_
Definition: diag.h:64
void IpHdr(uint16_t len, in_addr_t src, in_addr_t dest, uint8_t protocol, uint16_t id, uint8_t ttl)