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