OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ping.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include <stdint.h>
6 #include "base/os.h"
7 #include "vr_defs.h"
8 #include "cmn/agent_cmn.h"
9 #include "oper/nexthop.h"
10 #include "oper/route_common.h"
11 #include "oper/mirror_table.h"
12 #include "pkt/proto.h"
13 #include "pkt/proto_handler.h"
14 #include "diag/diag_types.h"
15 #include "diag/diag_pkt_handler.h"
16 #include "diag/diag.h"
17 #include "diag/ping.h"
18 
19 using namespace boost::posix_time;
20 
21 Ping::Ping(const PingReq *ping_req, DiagTable *diag_table):
22  DiagEntry(ping_req->get_source_ip(), ping_req->get_dest_ip(),
23  ping_req->get_protocol(), ping_req->get_source_port(),
24  ping_req->get_dest_port(), ping_req->get_vrf_name(),
25  ping_req->get_interval() * 100, ping_req->get_count(), diag_table),
26  data_len_(ping_req->get_packet_size()), context_(ping_req->context()),
27  pkt_lost_count_(0) {
28 
29 }
30 
32 }
33 
34 void
37  ad->key_ = htons(key_);
38  ad->seq_no_ = htonl(seq_no_);
39  ad->rtt_ = microsec_clock::universal_time();
40  memset(ad->data_, 0, sizeof(ad->data_));
41 }
42 
45  //Allocate buffer to hold packet
46  if (sip_.is_v4()) {
48  } else {
50  }
51  boost::shared_ptr<PktInfo> pkt_info(new PktInfo(agent, len_,
52  PktHandler::DIAG, 0));
53  uint8_t *msg = pkt_info->packet_buffer()->data();
54  memset(msg, 0, len_);
55 
56  AgentDiagPktData *ad;
57  if (sip_.is_v4()) {
58  ad = (AgentDiagPktData *)(msg + KPingTcpHdr);
59  } else {
60  ad = (AgentDiagPktData *)(msg + KPing6TcpHdr);
61  }
62 
63  FillAgentHeader(ad);
64  DiagPktHandler *pkt_handler = new DiagPktHandler(diag_table_->agent(), pkt_info,
65  *(diag_table_->agent()->event_manager())->io_service());
66 
67  //Update pointers to ethernet header, ip header and l4 header
68  if (sip_.is_v4()) {
69  pkt_info->UpdateHeaderPtr();
70  pkt_handler->TcpHdr(htonl(sip_.to_v4().to_ulong()), sport_,
71  htonl(dip_.to_v4().to_ulong()), dport_, false, rand(),
72  data_len_ + sizeof(tcphdr));
73  pkt_handler->IpHdr(data_len_ + sizeof(tcphdr) + sizeof(struct ip),
74  ntohl(sip_.to_v4().to_ulong()),
75  ntohl(dip_.to_v4().to_ulong()), IPPROTO_TCP,
77  pkt_handler->EthHdr(agent->vhost_interface()->mac(),
78  agent->vrrp_mac(), ETHERTYPE_IP);
79  }else {
80  pkt_info->eth = (struct ether_header *)(pkt_info->pkt);
81  pkt_info->ip6 = (struct ip6_hdr *)(pkt_info->eth + 1);
82  pkt_info->transp.tcp = (struct tcphdr *)(pkt_info->ip6 + 1);
83  pkt_handler->TcpHdr(data_len_ + sizeof(tcphdr),
84  (uint8_t *)sip_.to_v6().to_string().c_str(), sport_,
85  (uint8_t *)dip_.to_v6().to_string().c_str(), dport_,
86  false, rand(), IPPROTO_TCP);
87  pkt_handler->Ip6Hdr(pkt_info->ip6,
88  data_len_ + sizeof(tcphdr) + sizeof(struct ip6_hdr),
89  IPPROTO_TCP, DEFAULT_IP_TTL,
90  sip_.to_v6().to_bytes().data(),
91  dip_.to_v6().to_bytes().data());
92  pkt_handler->EthHdr(agent->vhost_interface()->mac(),
93  agent->vrrp_mac(), ETHERTYPE_IPV6);
94  }
95 
96  return pkt_handler;
97 }
98 
101  //Allocate buffer to hold packet
102  if (sip_.is_v4()) {
104  } else {
106  }
107  boost::shared_ptr<PktInfo> pkt_info(new PktInfo(agent, len_,
108  PktHandler::DIAG, 0));
109  uint8_t *msg = pkt_info->packet_buffer()->data();
110  memset(msg, 0, len_);
111 
112  AgentDiagPktData *ad;
113  if (sip_.is_v4()) {
114  ad = (AgentDiagPktData *)(msg + KPingUdpHdr);
115  } else {
116  ad = (AgentDiagPktData *)(msg + KPing6UdpHdr);
117  }
118 
119  FillAgentHeader(ad);
120 
121  DiagPktHandler *pkt_handler = new DiagPktHandler(diag_table_->agent(), pkt_info,
122  *(diag_table_->agent()->event_manager())->io_service());
123 
124  //Update pointers to ethernet header, ip header and l4 header
125  if (sip_.is_v4()) {
126  pkt_info->UpdateHeaderPtr();
127  pkt_handler->UdpHdr(data_len_+ sizeof(udphdr), sip_.to_v4().to_ulong(), sport_,
128  dip_.to_v4().to_ulong(), dport_);
129  pkt_handler->IpHdr(data_len_ + sizeof(udphdr) + sizeof(struct ip),
130  ntohl(sip_.to_v4().to_ulong()),
131  ntohl(dip_.to_v4().to_ulong()), IPPROTO_UDP,
133  pkt_handler->EthHdr(agent->vhost_interface()->mac(),
134  agent->vrrp_mac(), ETHERTYPE_IP);
135  } else {
136  pkt_info->eth = (struct ether_header *)(pkt_info->pkt);
137  pkt_info->ip6 = (struct ip6_hdr *)(pkt_info->eth + 1);
138  pkt_info->transp.udp = (struct udphdr *)(pkt_info->ip6 + 1);
139  pkt_handler->UdpHdr(data_len_ + sizeof(udphdr),
140  sip_.to_v6().to_bytes().data(), sport_,
141  dip_.to_v6().to_bytes().data(), dport_,
142  IPPROTO_UDP);
143  pkt_handler->Ip6Hdr(pkt_info->ip6,
144  data_len_ + sizeof(udphdr) + sizeof(struct ip6_hdr),
145  IPPROTO_UDP, DEFAULT_IP_TTL,
146  sip_.to_v6().to_bytes().data(),
147  dip_.to_v6().to_bytes().data());
148  pkt_handler->EthHdr(agent->vhost_interface()->mac(),
149  agent->vrrp_mac(), ETHERTYPE_IPV6);
150  }
151  return pkt_handler;
152 }
153 
155  Agent *agent = Agent::GetInstance();
156  DiagPktHandler *pkt_handler = NULL;
157  //Increment the attempt count
158  seq_no_++;
159  switch(proto_) {
160  case IPPROTO_TCP:
161  pkt_handler = CreateTcpPkt(agent);
162  break;
163 
164  case IPPROTO_UDP:
165  pkt_handler = CreateUdpPkt(agent);
166  break;
167  }
168 
170  if (sip_.is_v4()) {
171  table = agent->vrf_table()->GetInet4UnicastRouteTable(vrf_name_);
172  } else {
173  table = agent->vrf_table()->GetInet6UnicastRouteTable(vrf_name_);
174  }
175  AgentRoute *rt = table->FindRoute(sip_);
176  if (!rt) {
177  delete pkt_handler;
178  return;
179  }
180 
181  const NextHop *nh;
182  nh = rt->GetActiveNextHop();
183  if (!nh || nh->GetType() != NextHop::INTERFACE) {
184  delete pkt_handler;
185  return;
186  }
187 
188  const InterfaceNH *intf_nh;
189  intf_nh = static_cast<const InterfaceNH *>(nh);
190 
191  uint32_t intf_id = intf_nh->GetInterface()->id();
192  uint32_t vrf_id = diag_table_->agent()->vrf_table()->FindVrfFromName(vrf_name_)->vrf_id();
193  //Send request out
194  pkt_handler->SetDiagChkSum();
195  pkt_handler->pkt_info()->set_len(len_);
196  pkt_handler->Send(intf_id, vrf_id, AgentHdr::TX_ROUTE,
197  CMD_PARAM_PACKET_CTRL, CMD_PARAM_1_DIAG, PktHandler::DIAG);
198  delete pkt_handler;
199  return;
200 }
201 
202 void Ping::RequestTimedOut(uint32_t seqno) {
203  PingResp *resp = new PingResp();
204  pkt_lost_count_++;
205  resp->set_resp("Timed Out");
206  resp->set_seq_no(seqno);
207  resp->set_context(context_);
208  resp->set_more(true);
209  resp->Response();
210 }
211 
212 void time_duration_to_string(time_duration &td, std::string &str) {
213  std::ostringstream td_str;
214 
215  if (td.minutes()) {
216  td_str << td.minutes() << "m " << td.seconds() << "s";
217  } else if (td.total_milliseconds()) {
218  td_str << td.total_milliseconds() << "ms";
219  } else if (td.total_microseconds()) {
220  td_str << td.total_microseconds() << "us";
221  } else {
222  td_str << td.total_nanoseconds() << "ns";
223  }
224 
225  str = td_str.str();
226 }
227 
229  //Send reply
230  PingResp *resp = new PingResp();
231  AgentDiagPktData *ad = (AgentDiagPktData *)handler->GetData();
232 
233  resp->set_seq_no(ntohl(ad->seq_no_));
234 
235  //Calculate rtt
236  time_duration rtt = microsec_clock::universal_time() - ad->rtt_;
237  avg_rtt_ += rtt;
238  std::string rtt_str;
239  time_duration_to_string(rtt, rtt_str);
240  resp->set_rtt(rtt_str);
241 
242  resp->set_resp("Success");
243  resp->set_context(context_);
244  resp->set_more(true);
245  resp->Response();
246 }
247 
249  PingSummaryResp *resp = new PingSummaryResp();
250 
251  if (pkt_lost_count_ != GetMaxAttempts()) {
252  //If we had some succesful replies, send in
253  //average rtt for succesful ping requests
255  std::string avg_rtt_string;
256  time_duration_to_string(avg_rtt_, avg_rtt_string);
257  resp->set_average_rtt(avg_rtt_string);
258  }
259 
260  resp->set_request_sent(seq_no_);
261  resp->set_response_received(seq_no_ - pkt_lost_count_);
262  uint32_t pkt_loss_percent = (pkt_lost_count_ * 100/seq_no_);
263  resp->set_pkt_loss(pkt_loss_percent);
264  resp->set_context(context_);
265  resp->Response();
266 }
267 
268 void PingReq::HandleRequest() const {
269  std::string err_str;
270  boost::system::error_code ec;
271  Ping *ping = NULL;
272 
273  {
274  IpAddress sip(IpAddress::from_string(get_source_ip(), ec));
275  if (ec.failed()) {
276  err_str = "Invalid source IP";
277  goto error;
278  }
279 
280  IpAddress dip(IpAddress::from_string(get_dest_ip(), ec));
281  if (ec.failed()) {
282  err_str = "Invalid destination IP";
283  goto error;
284  }
285 
286  uint8_t proto = get_protocol();
287  if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
288  err_str = "Invalid protocol. Valid Protocols are TCP and UDP";
289  goto error;
290  }
291 
292  if (Agent::GetInstance()->vrf_table()->FindVrfFromName(get_vrf_name()) == NULL) {
293  err_str = "Invalid VRF";
294  goto error;
295  }
296 
297  const NextHop *nh = NULL;
298  Agent *agent = Agent::GetInstance();
300  if (sip.is_v4()) {
301  table = agent->vrf_table()->GetInet4UnicastRouteTable(get_vrf_name());
302  } else {
303  table = agent->vrf_table()->GetInet6UnicastRouteTable(get_vrf_name());
304  }
305  AgentRoute *rt = table->FindRoute(sip);
306  if (rt) {
307  nh = rt->GetActiveNextHop();
308  }
309  if (!nh || nh->GetType() != NextHop::INTERFACE) {
310  err_str = "VM not present on this server";
311  goto error;
312  }
313  }
314  ping = new Ping(this, Agent::GetInstance()->diag_table());
315  ping->Init();
316  return;
317 
318 error:
319  PingErrResp *resp = new PingErrResp;
320  resp->set_error_response(err_str);
321  resp->set_context(context());
322  resp->Response();
323  return;
324 }
IpAddress dip_
Definition: diag.h:57
const Interface * GetInterface() const
Definition: nexthop.h:1293
IpAddress sip_
Definition: diag.h:56
DiagPktHandler * CreateUdpPkt(Agent *agent)
Definition: ping.cc:100
uint32_t GetMaxAttempts()
Definition: diag.h:42
#define DEFAULT_IP_TTL
Definition: pkt_handler.h:44
static Agent * GetInstance()
Definition: agent.h:436
VrfEntry * FindVrfFromName(const string &name)
Definition: vrf.cc:873
const uint32_t id() const
Definition: interface.h:123
boost::posix_time::ptime rtt_
Definition: diag.h:86
const Interface * vhost_interface() const
Definition: agent.h:935
uint16_t data_len_
Definition: ping.h:37
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
#define DEFAULT_IP_ID
Definition: pkt_handler.h:48
uint32_t seq_no_
Definition: diag.h:84
void set_len(uint32_t len)
uint32_t op_
Definition: diag.h:82
uint16_t len_
Definition: ping.h:38
char data_[8]
Definition: diag.h:85
InetUnicastRouteEntry * FindRoute(const IpAddress &ip)
const MacAddress & mac() const
Definition: interface.h:131
static const uint32_t KPing6TcpHdr
Definition: ping.h:22
static const uint32_t KPingTcpHdr
Definition: ping.h:18
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
InetUnicastAgentRouteTable * GetInet4UnicastRouteTable(const std::string &vrf_name)
Definition: vrf.cc:898
int EthHdr(const MacAddress &src, const MacAddress &dest, const uint16_t proto)
void Init()
Definition: diag.cc:47
static const uint32_t KPingUdpHdr
Definition: ping.h:16
Ping(const PingReq *pr, DiagTable *diag_table)
Definition: ping.cc:21
Definition: agent.h:358
virtual ~Ping()
Definition: ping.cc:31
const NextHop * GetActiveNextHop() const
Definition: agent_route.cc:881
EventManager * event_manager() const
Definition: agent.h:1103
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
uint8_t * GetData()
Agent * agent() const
Definition: diag.h:117
Definition: ping.h:14
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)
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)
virtual void HandleReply(DiagPktHandler *handler)
Definition: ping.cc:228
VrfTable * vrf_table() const
Definition: agent.h:485
DiagPktHandler * CreateTcpPkt(Agent *agent)
Definition: ping.cc:44
uint16_t sport_
Definition: diag.h:59
void time_duration_to_string(time_duration &td, std::string &str)
Definition: ping.cc:212
void UdpHdr(uint16_t len, in_addr_t src, uint16_t src_port, in_addr_t dest, uint16_t dest_port)
virtual void RequestTimedOut(uint32_t seq_no)
Definition: ping.cc:202
boost::posix_time::time_duration avg_rtt_
Definition: ping.h:40
Definition: diag.h:21
uint32_t pkt_lost_count_
Definition: ping.h:41
virtual void SendRequest()
Definition: ping.cc:154
static const uint32_t KPing6UdpHdr
Definition: ping.h:20
InetUnicastAgentRouteTable * GetInet6UnicastRouteTable(const std::string &vrf_name)
Definition: vrf.cc:922
DiagKey key_
Definition: diag.h:65
void FillAgentHeader(AgentDiagPktData *pkt)
Definition: ping.cc:35
std::string context_
Definition: ping.h:39
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)
virtual void SendSummary()
Definition: ping.cc:248