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