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