Line data Source code
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 0 : TraceRoute::SendSandeshReply(const std::string &address,
23 : const std::string &context,
24 : bool more) {
25 0 : TraceRouteResp *resp = new TraceRouteResp();
26 0 : resp->set_hop(address);
27 :
28 0 : resp->set_context(context);
29 0 : resp->set_more(more);
30 0 : resp->Response();
31 0 : }
32 :
33 0 : TraceRoute::TraceRoute(const TraceRouteReq *trace_route_req,
34 0 : DiagTable *diag_table) :
35 : DiagEntry(trace_route_req->get_source_ip(), trace_route_req->get_dest_ip(),
36 0 : trace_route_req->get_protocol(), trace_route_req->get_source_port(),
37 0 : trace_route_req->get_dest_port(), trace_route_req->get_vrf_name(),
38 0 : trace_route_req->get_interval() * 100,
39 0 : trace_route_req->get_max_attempts(), diag_table),
40 0 : done_(false), ttl_(2),
41 0 : max_ttl_(trace_route_req->get_max_hops()),
42 0 : context_(trace_route_req->context()) {
43 0 : }
44 :
45 0 : TraceRoute::~TraceRoute() {
46 0 : }
47 :
48 0 : void TraceRoute::FillHeader(AgentDiagPktData *data) {
49 0 : data->op_ = htonl(AgentDiagPktData::DIAG_REQUEST);
50 0 : data->key_ = htons(key_);
51 0 : data->seq_no_ = htonl(seq_no_);
52 0 : memset(data->data_, 0, sizeof(data->data_));
53 : // data->rtt_ = microsec_clock::universal_time();
54 0 : }
55 :
56 0 : void TraceRoute::SendRequest() {
57 0 : Agent *agent = diag_table_->agent();
58 :
59 : InetUnicastAgentRouteTable *table;
60 0 : if (sip_.is_v4()) {
61 0 : table = agent->vrf_table()->GetInet4UnicastRouteTable(vrf_name_);
62 : } else {
63 0 : table = agent->vrf_table()->GetInet6UnicastRouteTable(vrf_name_);
64 : }
65 0 : AgentRoute *rt = table->FindRoute(sip_);
66 0 : if (!rt) return;
67 :
68 0 : const NextHop *nh = rt->GetActiveNextHop();
69 0 : if (!nh || nh->GetType() != NextHop::INTERFACE) return;
70 :
71 : const InterfaceNH *intf_nh;
72 0 : intf_nh = static_cast<const InterfaceNH *>(nh);
73 :
74 0 : uint32_t intf_id = intf_nh->GetInterface()->id();
75 0 : 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 0 : PktHandler::DIAG, 0));
80 0 : uint8_t *msg = pkt_info->packet_buffer()->data();
81 0 : memset(msg, 0, kBufferSize);
82 :
83 : DiagPktHandler *pkt_handler =
84 : new DiagPktHandler(agent, pkt_info,
85 0 : *(agent->event_manager())->io_service());
86 0 : uint16_t len = sizeof(AgentDiagPktData);
87 0 : uint8_t *data = NULL;
88 0 : if (sip_.is_v4()) {
89 : //Update pointers to ethernet header, ip header and l4 header
90 0 : pkt_info->UpdateHeaderPtr();
91 0 : switch (proto_) {
92 0 : case IPPROTO_TCP:
93 0 : len += sizeof(tcphdr);
94 0 : data = (uint8_t *)pkt_handler->pkt_info()->transp.tcp + sizeof(tcphdr);
95 0 : pkt_handler->TcpHdr(htonl(sip_.to_v4().to_ulong()), sport_,
96 0 : htonl(dip_.to_v4().to_ulong()), dport_,
97 0 : false, rand(), len);
98 0 : pkt_handler->pkt_info()->transp.tcp->check = 0xffff;
99 0 : break;
100 :
101 0 : case IPPROTO_UDP:
102 0 : len += sizeof(udphdr);
103 0 : data = (uint8_t *)pkt_handler->pkt_info()->transp.udp + sizeof(udphdr);
104 0 : pkt_handler->UdpHdr(len, sip_.to_v4().to_ulong(), sport_,
105 0 : dip_.to_v4().to_ulong(), dport_);
106 0 : pkt_handler->pkt_info()->transp.udp->check = 0xffff;
107 0 : break;
108 :
109 0 : case IPPROTO_ICMP:
110 0 : len += 8;
111 0 : data = (uint8_t *)pkt_handler->pkt_info()->transp.icmp + 8;
112 0 : pkt_handler->pkt_info()->transp.icmp->icmp_type = ICMP_ECHO;
113 0 : pkt_handler->pkt_info()->transp.icmp->icmp_code = 0;
114 0 : pkt_handler->pkt_info()->transp.icmp->icmp_cksum = 0xffff;
115 0 : break;
116 : }
117 0 : FillHeader((AgentDiagPktData *)data);
118 0 : len += sizeof(struct ip);
119 0 : pkt_handler->IpHdr(len, ntohl(sip_.to_v4().to_ulong()),
120 0 : ntohl(dip_.to_v4().to_ulong()),
121 0 : proto_, key_, ttl_);
122 0 : len += sizeof(ether_header);
123 0 : pkt_handler->EthHdr(agent->vhost_interface()->mac(),
124 : agent->vrrp_mac(), ETHERTYPE_IP);
125 : } else {
126 0 : pkt_info->eth = (struct ether_header *)(pkt_handler->pkt_info()->pkt);
127 0 : pkt_info->ip6 = (struct ip6_hdr *)(pkt_info->eth + 1);
128 0 : switch (proto_) {
129 0 : case IPPROTO_TCP:
130 0 : pkt_info->transp.tcp = (struct tcphdr *)(pkt_info->ip6 + 1);
131 0 : len += sizeof(tcphdr);
132 0 : data = (uint8_t *)pkt_handler->pkt_info()->transp.tcp + sizeof(tcphdr);
133 0 : pkt_handler->TcpHdr(len+sizeof(tcphdr),
134 0 : sip_.to_v6().to_bytes().data(), sport_,
135 0 : dip_.to_v6().to_bytes().data(), dport_,
136 0 : false, rand(), IPPROTO_TCP);
137 0 : pkt_handler->pkt_info()->transp.tcp->check = 0xffff;
138 0 : break;
139 :
140 0 : case IPPROTO_UDP:
141 0 : pkt_info->transp.udp = (struct udphdr *)(pkt_info->ip6 + 1);
142 0 : len += sizeof(udphdr);
143 0 : data = (uint8_t *)pkt_handler->pkt_info()->transp.udp + sizeof(udphdr);
144 0 : pkt_handler->UdpHdr(len + sizeof(udphdr),
145 0 : sip_.to_v6().to_bytes().data(), sport_,
146 0 : dip_.to_v6().to_bytes().data(), dport_,
147 : IPPROTO_UDP);
148 0 : pkt_handler->pkt_info()->transp.udp->check = 0xffff;
149 0 : break;
150 :
151 0 : case IPPROTO_ICMPV6:
152 0 : len += 8;
153 0 : data = (uint8_t *)pkt_handler->pkt_info()->transp.icmp + 8;
154 0 : pkt_handler->pkt_info()->transp.icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
155 0 : pkt_handler->pkt_info()->transp.icmp6->icmp6_code = 0;
156 0 : pkt_handler->pkt_info()->transp.icmp6->icmp6_cksum = 0xffff;
157 0 : break;
158 : }
159 0 : FillHeader((AgentDiagPktData *)data);
160 0 : len += sizeof(struct ip6_hdr);
161 0 : pkt_handler->Ip6Hdr(pkt_info->ip6,
162 0 : len + sizeof(udphdr) + sizeof(struct ip6_hdr),
163 0 : IPPROTO_UDP, ttl_, sip_.to_v6().to_bytes().data(),
164 0 : dip_.to_v6().to_bytes().data());
165 0 : len += sizeof(ether_header);
166 0 : pkt_handler->EthHdr(agent->vhost_interface()->mac(),
167 : agent->vrrp_mac(), ETHERTYPE_IPV6);
168 : }
169 : //Increment the attempt count
170 0 : seq_no_++;
171 :
172 : //Send request out
173 0 : pkt_handler->pkt_info()->set_len(len);
174 0 : pkt_handler->Send(intf_id, vrf_id, AgentHdr::TX_ROUTE,
175 : CMD_PARAM_PACKET_CTRL, CMD_PARAM_1_DIAG, PktHandler::DIAG);
176 0 : delete pkt_handler;
177 0 : return;
178 0 : }
179 :
180 : // if timed out max times for a TTL, reply and increment ttl
181 0 : void TraceRoute::RequestTimedOut(uint32_t seqno) {
182 0 : if (seq_no_ >= GetMaxAttempts()) {
183 0 : std::string address;
184 0 : for (uint32_t i = 0; i < GetMaxAttempts(); i++)
185 0 : address += "* ";
186 :
187 0 : done_ = ((ttl_ >= max_ttl_) ? true : false);
188 0 : SendSandeshReply(address, context_, !done_);
189 0 : IncrementTtl();
190 0 : }
191 0 : }
192 :
193 : // Ready to send a response and increment ttl
194 0 : void TraceRoute::HandleReply(DiagPktHandler *handler) {
195 0 : if (ttl_ >= max_ttl_) {
196 0 : handler->set_done(true);
197 0 : done_ = true;
198 : }
199 0 : SendSandeshReply(handler->GetAddress(), context_, !handler->IsDone());
200 0 : IncrementTtl();
201 0 : }
202 :
203 : // Reply with local node as the first hop
204 0 : void TraceRoute::ReplyLocalHop() {
205 0 : SendSandeshReply(diag_table_->agent()->router_id().to_string(),
206 0 : context_, true);
207 0 : }
208 :
209 0 : void TraceRoute::SendSummary() {
210 0 : }
211 :
212 0 : bool TraceRoute::IsDone() {
213 0 : return done_;
214 : }
215 :
216 0 : void TraceRoute::IncrementTtl() {
217 0 : ttl_++;
218 0 : seq_no_ = 0;
219 0 : }
220 :
221 0 : void TraceRouteReq::HandleRequest() const {
222 0 : std::string err_str;
223 0 : boost::system::error_code ec;
224 0 : TraceRoute *trace_route = NULL;
225 :
226 : {
227 0 : IpAddress sip(IpAddress::from_string(get_source_ip(), ec));
228 0 : if (ec.failed()) {
229 0 : err_str = "Invalid source IP";
230 0 : goto error;
231 : }
232 :
233 0 : IpAddress dip(IpAddress::from_string(get_dest_ip(), ec));
234 0 : if (ec.failed()) {
235 0 : err_str = "Invalid destination IP";
236 0 : goto error;
237 : }
238 :
239 0 : uint8_t proto = get_protocol();
240 0 : if (proto != IPPROTO_TCP && proto != IPPROTO_UDP && proto != IPPROTO_ICMP) {
241 0 : err_str = "Invalid protocol - Supported protocols are TCP, UDP and ICMP";
242 0 : goto error;
243 : }
244 :
245 0 : if (Agent::GetInstance()->vrf_table()->FindVrfFromName(get_vrf_name()) == NULL) {
246 0 : err_str = "Invalid VRF";
247 0 : goto error;
248 : }
249 :
250 0 : const NextHop *nh = NULL;
251 0 : Agent *agent = Agent::GetInstance();
252 : InetUnicastAgentRouteTable *table;
253 0 : if (sip.is_v4()) {
254 0 : table = agent->vrf_table()->GetInet4UnicastRouteTable(get_vrf_name());
255 : } else {
256 0 : table = agent->vrf_table()->GetInet6UnicastRouteTable(get_vrf_name());
257 : }
258 0 : AgentRoute *rt = table->FindRoute(sip);
259 0 : if (rt) {
260 0 : nh = rt->GetActiveNextHop();
261 : }
262 0 : if (!nh || nh->GetType() != NextHop::INTERFACE) {
263 0 : err_str = "Source VM is not present in this server";
264 0 : goto error;
265 : }
266 :
267 0 : rt = table->FindRoute(dip);
268 0 : if (rt) {
269 0 : nh = rt->GetActiveNextHop();
270 0 : if (nh && nh->GetType() == NextHop::INTERFACE) {
271 : // Dest VM is also local
272 0 : TraceRoute::SendSandeshReply(agent->router_id().to_string(),
273 0 : context(), false);
274 0 : return;
275 : }
276 : }
277 : }
278 :
279 0 : trace_route = new TraceRoute(this, Agent::GetInstance()->diag_table());
280 0 : trace_route->ReplyLocalHop();
281 0 : trace_route->Init();
282 0 : return;
283 :
284 0 : error:
285 0 : TraceRouteErrResp *resp = new TraceRouteErrResp;
286 0 : resp->set_error_response(err_str);
287 0 : resp->set_context(context());
288 0 : resp->Response();
289 0 : return;
290 0 : }
|