blob: 3b869b66ead1510b2cd7ab464ac787e74bb47930 [file] [log] [blame]
daniel park128c52c2017-09-04 13:15:51 +09001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.openstacknetworkingui;
17
18import com.fasterxml.jackson.databind.ObjectMapper;
Daniel Park819f4e82018-07-02 14:22:31 +090019import com.fasterxml.jackson.databind.node.ArrayNode;
daniel park128c52c2017-09-04 13:15:51 +090020import com.fasterxml.jackson.databind.node.ObjectNode;
Daniel Park577b69c2018-07-16 17:29:34 +090021import com.google.common.base.Charsets;
daniel park128c52c2017-09-04 13:15:51 +090022import com.google.common.base.Strings;
23import com.google.common.collect.ImmutableSet;
24import com.google.common.collect.Lists;
25import com.google.common.collect.Sets;
26import com.google.common.collect.Streams;
Daniel Park577b69c2018-07-16 17:29:34 +090027import org.apache.sshd.client.SshClient;
28import org.apache.sshd.client.channel.ClientChannel;
29import org.apache.sshd.client.channel.ClientChannelEvent;
30import org.apache.sshd.client.future.OpenFuture;
31import org.apache.sshd.client.session.ClientSession;
32import org.apache.sshd.common.util.io.NoCloseInputStream;
daniel park128c52c2017-09-04 13:15:51 +090033import org.onlab.osgi.ServiceDirectory;
Daniel Park577b69c2018-07-16 17:29:34 +090034import org.onlab.packet.IpAddress;
daniel park128c52c2017-09-04 13:15:51 +090035import org.onosproject.net.Device;
36import org.onosproject.net.DeviceId;
37import org.onosproject.net.Element;
38import org.onosproject.net.Host;
39import org.onosproject.net.HostId;
40import org.onosproject.net.Path;
41import org.onosproject.net.device.DeviceService;
42import org.onosproject.net.host.HostService;
43import org.onosproject.net.topology.PathService;
Daniel Park577b69c2018-07-16 17:29:34 +090044import org.onosproject.openstacknetworking.api.InstancePort;
45import org.onosproject.openstacknetworking.api.InstancePortService;
46import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
47import org.onosproject.openstacknode.api.OpenstackNode;
48import org.onosproject.openstacknode.api.OpenstackNodeService;
49import org.onosproject.openstacknode.api.OpenstackSshAuth;
daniel park128c52c2017-09-04 13:15:51 +090050import org.onosproject.ui.JsonUtils;
51import org.onosproject.ui.RequestHandler;
52import org.onosproject.ui.UiConnection;
53import org.onosproject.ui.UiMessageHandler;
daniel park128c52c2017-09-04 13:15:51 +090054import org.onosproject.ui.topo.Highlights;
55import org.onosproject.ui.topo.HostHighlight;
56import org.onosproject.ui.topo.NodeBadge;
57import org.onosproject.ui.topo.NodeBadge.Status;
58import org.onosproject.ui.topo.TopoJson;
59import org.slf4j.Logger;
60import org.slf4j.LoggerFactory;
61
daniel park128c52c2017-09-04 13:15:51 +090062import java.io.ByteArrayInputStream;
Daniel Park577b69c2018-07-16 17:29:34 +090063import java.io.ByteArrayOutputStream;
daniel park128c52c2017-09-04 13:15:51 +090064import java.io.InputStream;
Daniel Park577b69c2018-07-16 17:29:34 +090065import java.io.OutputStream;
daniel park128c52c2017-09-04 13:15:51 +090066import java.util.Collection;
67import java.util.List;
Daniel Park577b69c2018-07-16 17:29:34 +090068import java.util.Optional;
daniel park128c52c2017-09-04 13:15:51 +090069import java.util.Set;
Daniel Park577b69c2018-07-16 17:29:34 +090070import java.util.concurrent.ExecutorService;
71import java.util.concurrent.TimeUnit;
daniel park128c52c2017-09-04 13:15:51 +090072
Daniel Park577b69c2018-07-16 17:29:34 +090073import static java.util.concurrent.Executors.newSingleThreadExecutor;
74import static org.onlab.util.Tools.groupedThreads;
daniel park128c52c2017-09-04 13:15:51 +090075import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
Daniel Park577b69c2018-07-16 17:29:34 +090076import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
daniel park128c52c2017-09-04 13:15:51 +090077
78/**
79 * OpenStack Networking UI message handler.
80 */
81public class OpenstackNetworkingUiMessageHandler extends UiMessageHandler {
82
83 private static final String OPENSTACK_NETWORKING_UI_START = "openstackNetworkingUiStart";
84 private static final String OPENSTACK_NETWORKING_UI_UPDATE = "openstackNetworkingUiUpdate";
85 private static final String OPENSTACK_NETWORKING_UI_STOP = "openstackNetworkingUiStop";
86 private static final String ANNOTATION_NETWORK_ID = "networkId";
87 private static final String FLOW_TRACE_REQUEST = "flowTraceRequest";
88 private static final String SRC_IP = "srcIp";
89 private static final String DST_IP = "dstIp";
90 private static final String ANNOTATION_SEGMENT_ID = "segId";
daniel park128c52c2017-09-04 13:15:51 +090091
92 private static final String ID = "id";
93 private static final String MODE = "mode";
94 private static final String MOUSE = "mouse";
Daniel Park577b69c2018-07-16 17:29:34 +090095 private static final String TRACE_RESULT = "traceResult";
96 private static final String IS_SUCCESS = "isSuccess";
97 private static final String TRACE_SUCCESS = "traceSuccess";
98 private static final String FLOW_TRACE_RESULT = "flowTraceResult";
99 private static final String SRC_DEVICE_ID = "srcDeviceId";
100 private static final String DST_DEVICE_ID = "dstDeviceId";
Daniel Park4e037f52018-09-20 18:04:18 +0900101 private static final String UPLINK = "uplink";
Daniel Park577b69c2018-07-16 17:29:34 +0900102 private static final String OVS_VERSION_2_8 = "2.8";
Daniel Park4e037f52018-09-20 18:04:18 +0900103 private static final String OVS_VERSION_2_7 = "2.7";
Daniel Park577b69c2018-07-16 17:29:34 +0900104 private static final String OVS_VERSION_2_6 = "2.6";
Daniel Park4e037f52018-09-20 18:04:18 +0900105
Daniel Park577b69c2018-07-16 17:29:34 +0900106 private static final String VXLAN = "VXLAN";
107 private static final String VLAN = "VLAN";
108 private static final String DL_DST = "dl_dst=";
109 private static final String NW_DST = "nw_dst=";
Daniel Park4e037f52018-09-20 18:04:18 +0900110 private static final String DEFAULT_REQUEST_STRING = "sudo ovs-appctl ofproto/trace br-int ip";
111 private static final String IN_PORT = "in_port=";
Daniel Park577b69c2018-07-16 17:29:34 +0900112 private static final String NW_SRC = "nw_src=";
113 private static final String COMMA = ",";
Daniel Park4e037f52018-09-20 18:04:18 +0900114 private static final String TUN_ID = "tun_id=";
Daniel Park577b69c2018-07-16 17:29:34 +0900115
116 private static final long TIMEOUT_MS = 5000;
117 private static final long WAIT_OUTPUT_STREAM_SECOND = 2;
118 private static final int SSH_PORT = 22;
daniel park128c52c2017-09-04 13:15:51 +0900119
120 private enum Mode { IDLE, MOUSE }
121
122 private final Logger log = LoggerFactory.getLogger(getClass());
123
124 private DeviceService deviceService;
125 private HostService hostService;
126 private PathService pathService;
Daniel Park577b69c2018-07-16 17:29:34 +0900127 private OpenstackNodeService osNodeService;
128 private InstancePortService instancePortService;
129 private OpenstackNetworkService osNetService;
daniel park128c52c2017-09-04 13:15:51 +0900130 private Mode currentMode = Mode.IDLE;
131 private Element elementOfNote;
daniel park128c52c2017-09-04 13:15:51 +0900132
Daniel Park577b69c2018-07-16 17:29:34 +0900133 private final ExecutorService eventExecutor = newSingleThreadExecutor(
134 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
daniel park128c52c2017-09-04 13:15:51 +0900135
136 @Override
137 public void init(UiConnection connection, ServiceDirectory directory) {
138 super.init(connection, directory);
139 deviceService = directory.get(DeviceService.class);
140 hostService = directory.get(HostService.class);
141 pathService = directory.get(PathService.class);
Daniel Park577b69c2018-07-16 17:29:34 +0900142 osNodeService = directory.get(OpenstackNodeService.class);
143 instancePortService = directory.get(InstancePortService.class);
144 osNetService = directory.get(OpenstackNetworkService.class);
daniel park128c52c2017-09-04 13:15:51 +0900145 }
146
daniel park128c52c2017-09-04 13:15:51 +0900147 @Override
148 protected Collection<RequestHandler> createRequestHandlers() {
149 return ImmutableSet.of(
150 new DisplayStartHandler(),
151 new DisplayUpdateHandler(),
152 new DisplayStopHandler(),
153 new FlowTraceRequestHandler()
154 );
155 }
156
daniel park128c52c2017-09-04 13:15:51 +0900157 private final class DisplayStartHandler extends RequestHandler {
158
159 public DisplayStartHandler() {
160 super(OPENSTACK_NETWORKING_UI_START);
161 }
162
163 @Override
164 public void process(ObjectNode payload) {
165 String mode = string(payload, MODE);
166
167 log.debug("Start Display: mode [{}]", mode);
168 clearState();
169 clearForMode();
170
171 switch (mode) {
172 case MOUSE:
173 currentMode = Mode.MOUSE;
Jian Lib7873422018-08-18 22:34:39 +0900174 eventExecutor.execute(OpenstackNetworkingUiMessageHandler.this::sendMouseData);
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900175
daniel park128c52c2017-09-04 13:15:51 +0900176 break;
177
178 default:
179 currentMode = Mode.IDLE;
180 break;
181 }
182 }
183 }
184
185 private final class FlowTraceRequestHandler extends RequestHandler {
186 public FlowTraceRequestHandler() {
187 super(FLOW_TRACE_REQUEST);
188 }
189
190 @Override
191 public void process(ObjectNode payload) {
192 String srcIp = string(payload, SRC_IP);
193 String dstIp = string(payload, DST_IP);
Daniel Park577b69c2018-07-16 17:29:34 +0900194 String srcDeviceId = string(payload, SRC_DEVICE_ID);
195 String dstDeviceId = string(payload, DST_DEVICE_ID);
Daniel Park4e037f52018-09-20 18:04:18 +0900196 boolean uplink = bool(payload, UPLINK);
197 log.info("Flow trace request called with" +
198 "src IP: {}, dst IP: {}, src device ID: {}, dst device Id: {}, uplink: ",
Daniel Park577b69c2018-07-16 17:29:34 +0900199 srcIp,
200 dstIp,
201 srcDeviceId,
Daniel Park4e037f52018-09-20 18:04:18 +0900202 dstDeviceId,
203 uplink);
204 eventExecutor.execute(() -> processFlowTraceRequest(srcIp, dstIp, srcDeviceId, dstDeviceId, uplink));
daniel park128c52c2017-09-04 13:15:51 +0900205 }
206 }
207
daniel park128c52c2017-09-04 13:15:51 +0900208 private final class DisplayUpdateHandler extends RequestHandler {
209 public DisplayUpdateHandler() {
210 super(OPENSTACK_NETWORKING_UI_UPDATE);
211 }
212
213 @Override
214 public void process(ObjectNode payload) {
215 String id = string(payload, ID);
216 log.debug("Update Display: id [{}]", id);
217 if (!Strings.isNullOrEmpty(id)) {
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900218 eventExecutor.execute(() -> updateForMode(id));
daniel park128c52c2017-09-04 13:15:51 +0900219 } else {
Jian Lib7873422018-08-18 22:34:39 +0900220 eventExecutor.execute(OpenstackNetworkingUiMessageHandler.this::clearForMode);
daniel park128c52c2017-09-04 13:15:51 +0900221 }
222 }
223 }
224
225 private final class DisplayStopHandler extends RequestHandler {
226 public DisplayStopHandler() {
227 super(OPENSTACK_NETWORKING_UI_STOP);
228 }
229
230 @Override
231 public void process(ObjectNode payload) {
232 log.debug("Stop Display");
233 clearState();
234 clearForMode();
235 }
236 }
237
daniel park128c52c2017-09-04 13:15:51 +0900238 private void clearState() {
239 currentMode = Mode.IDLE;
240 elementOfNote = null;
241 }
242
243 private void updateForMode(String id) {
244
245 try {
246 HostId hid = HostId.hostId(id);
247 elementOfNote = hostService.getHost(hid);
248
249 } catch (Exception e) {
250 try {
251 DeviceId did = DeviceId.deviceId(id);
252 elementOfNote = deviceService.getDevice(did);
253
254 } catch (Exception e2) {
255 log.debug("Unable to process ID [{}]", id);
256 elementOfNote = null;
257 }
258 }
259
260 switch (currentMode) {
261 case MOUSE:
262 sendMouseData();
263 break;
264
265 default:
266 break;
267 }
268
269 }
270
271 private void clearForMode() {
272 sendHighlights(new Highlights());
273 }
274
275 private void sendHighlights(Highlights highlights) {
276 sendMessage(TopoJson.highlightsMessage(highlights));
277 }
278
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900279 /**
280 * Sends JSON-based message to UI.
281 * @param type type
282 * @param payload payload
283 */
daniel park128c52c2017-09-04 13:15:51 +0900284 public void sendMessagetoUi(String type, ObjectNode payload) {
285 sendMessage(JsonUtils.envelope(type, payload));
286 }
287
288 private int getVni(Host host) {
289 String vni = host.annotations().value(ANNOTATION_SEGMENT_ID);
290
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900291 return vni == null ? 0 : Integer.parseInt(vni);
daniel park128c52c2017-09-04 13:15:51 +0900292 }
293
294 private void sendMouseData() {
295 Highlights highlights = new Highlights();
296
Jian Lib7873422018-08-18 22:34:39 +0900297 if (elementOfNote instanceof Device) {
daniel park128c52c2017-09-04 13:15:51 +0900298 DeviceId deviceId = (DeviceId) elementOfNote.id();
299
300 List<OpenstackLink> edgeLinks = edgeLinks(deviceId);
301
Jian Lib7873422018-08-18 22:34:39 +0900302 edgeLinks.forEach(edgeLink ->
303 highlights.add(edgeLink.highlight(OpenstackLink.RequestType.DEVICE_SELECTED)));
daniel park128c52c2017-09-04 13:15:51 +0900304
305 hostService.getConnectedHosts(deviceId).forEach(host -> {
306 HostHighlight hostHighlight = new HostHighlight(host.id().toString());
307 hostHighlight.setBadge(createBadge(getVni(host)));
308 highlights.add(hostHighlight);
309 });
310
311 sendHighlights(highlights);
312
Jian Lib7873422018-08-18 22:34:39 +0900313 } else if (elementOfNote instanceof Host) {
daniel park128c52c2017-09-04 13:15:51 +0900314
315 HostId hostId = HostId.hostId(elementOfNote.id().toString());
316 if (!hostMadeFromOpenstack(hostId)) {
317 return;
318 }
319
320 List<OpenstackLink> openstackLinks = linksInSameNetwork(hostId);
321
Jian Lib7873422018-08-18 22:34:39 +0900322 openstackLinks.forEach(openstackLink ->
323 highlights.add(openstackLink.highlight(OpenstackLink.RequestType.HOST_SELECTED)));
daniel park128c52c2017-09-04 13:15:51 +0900324
325 hostHighlightsInSameNetwork(hostId).forEach(highlights::add);
326
327 sendHighlights(highlights);
328
329 }
330 }
331
332 private boolean hostMadeFromOpenstack(HostId hostId) {
Jian Lib7873422018-08-18 22:34:39 +0900333 return hostService.getHost(hostId).annotations().value(ANNOTATION_NETWORK_ID) != null;
daniel park128c52c2017-09-04 13:15:51 +0900334 }
335
336 private String networkId(HostId hostId) {
337 return hostService.getHost(hostId).annotations().value(ANNOTATION_NETWORK_ID);
338 }
339
340 private Set<HostHighlight> hostHighlightsInSameNetwork(HostId hostId) {
341
342 Set<HostHighlight> hostHighlights = Sets.newHashSet();
343 Streams.stream(hostService.getHosts())
344 .filter(host -> isHostInSameNetwork(host, networkId(hostId)))
345 .forEach(host -> {
346 HostHighlight hostHighlight = new HostHighlight(host.id().toString());
347 hostHighlight.setBadge(createBadge(getVni(host)));
348 hostHighlights.add(hostHighlight);
349 });
350
351 return hostHighlights;
352 }
353
354 private List<OpenstackLink> edgeLinks(DeviceId deviceId) {
355 OpenstackLinkMap openstackLinkMap = new OpenstackLinkMap();
356
357 hostService.getConnectedHosts(deviceId).forEach(host -> {
358 openstackLinkMap.add(createEdgeLink(host, true));
359 openstackLinkMap.add(createEdgeLink(host, false));
360 });
361
362 List<OpenstackLink> edgeLinks = Lists.newArrayList();
363
Jian Lib7873422018-08-18 22:34:39 +0900364 edgeLinks.addAll(openstackLinkMap.biLinks());
daniel park128c52c2017-09-04 13:15:51 +0900365
366 return edgeLinks;
367 }
368
369 private List<OpenstackLink> linksInSameNetwork(HostId hostId) {
370 OpenstackLinkMap linkMap = new OpenstackLinkMap();
371
372 Streams.stream(hostService.getHosts())
373 .filter(host -> isHostInSameNetwork(host, networkId(hostId)))
374 .forEach(host -> {
375 linkMap.add(createEdgeLink(host, true));
376 linkMap.add(createEdgeLink(host, false));
377
378 Set<Path> paths = pathService.getPaths(hostId,
379 host.id());
380
381 if (!paths.isEmpty()) {
382 paths.forEach(path -> path.links().forEach(linkMap::add));
383 }
384 });
385
386 List<OpenstackLink> openstackLinks = Lists.newArrayList();
387
Jian Lib7873422018-08-18 22:34:39 +0900388 openstackLinks.addAll(linkMap.biLinks());
daniel park128c52c2017-09-04 13:15:51 +0900389
390 return openstackLinks;
391 }
392
393 private boolean isHostInSameNetwork(Host host, String networkId) {
394 return hostService.getHost(host.id()).annotations()
395 .value(ANNOTATION_NETWORK_ID).equals(networkId);
396 }
397
398 private NodeBadge createBadge(int n) {
399 return NodeBadge.number(Status.INFO, n, "Openstack Node");
400 }
Daniel Park577b69c2018-07-16 17:29:34 +0900401
Daniel Park4e037f52018-09-20 18:04:18 +0900402 private void processFlowTraceRequest(String srcIp, String dstIp, String srcDeviceId, String dstDeviceId,
403 boolean uplink) {
Daniel Park577b69c2018-07-16 17:29:34 +0900404 boolean traceSuccess = true;
405
406 ObjectMapper mapper = new ObjectMapper();
407
408 ObjectNode traceResult = mapper.createObjectNode();
409
410 ArrayNode traceResultArray = traceResult.putArray(TRACE_RESULT);
411
412 OpenstackNode srcOpenstackNode = osNodeService.node(DeviceId.deviceId(srcDeviceId));
413 if (srcOpenstackNode == null) {
Daniel Park4e037f52018-09-20 18:04:18 +0900414 log.error("There's no openstack node information for device {}", srcDeviceId);
Daniel Park577b69c2018-07-16 17:29:34 +0900415 return;
416 }
417
418 if (srcOpenstackNode.sshAuthInfo() == null) {
419 log.error("Openstack node {} has no SSH authentication information..",
420 srcOpenstackNode.hostname());
421 return;
422 }
423
Daniel Park4e037f52018-09-20 18:04:18 +0900424 String traceResultString = sendTraceRequestToNode(srcIp, dstIp, srcOpenstackNode, uplink);
425
426 if (traceResultString == null) {
Daniel Park577b69c2018-07-16 17:29:34 +0900427 return;
428 }
429
Daniel Park4e037f52018-09-20 18:04:18 +0900430 log.debug("traceResultString raw data: {}", traceResultString);
Daniel Park577b69c2018-07-16 17:29:34 +0900431
Daniel Park4e037f52018-09-20 18:04:18 +0900432 ObjectNode traceResultJson = null;
Daniel Park577b69c2018-07-16 17:29:34 +0900433
434 Device srcDevice = deviceService.getDevice(srcOpenstackNode.intgBridge());
Daniel Park4e037f52018-09-20 18:04:18 +0900435 if (srcDevice.swVersion().startsWith(OVS_VERSION_2_8) ||
436 srcDevice.swVersion().startsWith(OVS_VERSION_2_7)) {
437 traceResultJson = Ovs28FlowTraceResultParser.flowTraceResultInJson(
438 traceResultString.trim(), srcOpenstackNode.hostname());
Daniel Park577b69c2018-07-16 17:29:34 +0900439 } else {
440 log.error("Currently OVS version {} is not supported",
441 deviceService.getDevice(srcOpenstackNode.intgBridge()));
442 }
443
Daniel Park4e037f52018-09-20 18:04:18 +0900444 if (traceResultJson == null) {
Daniel Park577b69c2018-07-16 17:29:34 +0900445 return;
446 }
447
Daniel Park4e037f52018-09-20 18:04:18 +0900448 traceResultArray.add(traceResultJson);
Daniel Park577b69c2018-07-16 17:29:34 +0900449
Daniel Park4e037f52018-09-20 18:04:18 +0900450 log.debug("traceResultForward Json: {}", traceResultJson);
Daniel Park577b69c2018-07-16 17:29:34 +0900451
Daniel Park4e037f52018-09-20 18:04:18 +0900452 if (!traceResultJson.get(IS_SUCCESS).asBoolean()) {
Daniel Park577b69c2018-07-16 17:29:34 +0900453 traceSuccess = false;
454 }
455
Daniel Park577b69c2018-07-16 17:29:34 +0900456 traceResult.put(TRACE_SUCCESS, traceSuccess);
Daniel Park4e037f52018-09-20 18:04:18 +0900457
458 traceResult.put(SRC_IP, srcIp);
459 traceResult.put(DST_IP, dstIp);
460 traceResult.put(SRC_DEVICE_ID, srcDeviceId);
461 traceResult.put(DST_DEVICE_ID, dstDeviceId);
462 traceResult.put(UPLINK, uplink);
463
Daniel Park577b69c2018-07-16 17:29:34 +0900464 log.debug("traceResult Json: {}", traceResult);
465
466 sendMessagetoUi(FLOW_TRACE_RESULT, traceResult);
467
468 }
469
Daniel Park4e037f52018-09-20 18:04:18 +0900470 private String sendTraceRequestToNode(String srcIp, String dstIp, OpenstackNode openstackNode, boolean uplink) {
471
472 Optional<InstancePort> instancePort = instancePortService.instancePorts().stream()
473 .filter(port -> port.ipAddress().getIp4Address().toString().equals(srcIp)
474 && port.deviceId().equals(openstackNode.intgBridge()))
475 .findAny();
476
477 if (!instancePort.isPresent()) {
478 return null;
479 }
480
481 String requestString = traceRequestString(srcIp, dstIp,
482 instancePort.get(), osNetService, uplink);
483
484 return sendTraceRequestToNode(requestString, openstackNode);
485 }
486
487 private String traceRequestString(String srcIp,
488 String dstIp,
489 InstancePort srcInstancePort,
490 OpenstackNetworkService osNetService,
491 boolean uplink) {
492
493 StringBuilder requestStringBuilder = new StringBuilder(DEFAULT_REQUEST_STRING);
494
495 if (uplink) {
496
497 requestStringBuilder.append(COMMA)
498 .append(IN_PORT)
499 .append(srcInstancePort.portNumber().toString())
500 .append(COMMA)
501 .append(NW_SRC)
502 .append(srcIp)
503 .append(COMMA);
504
505 if (osNetService.networkType(srcInstancePort.networkId()).equals(VXLAN) ||
506 osNetService.networkType(srcInstancePort.networkId()).equals(VLAN)) {
507 if (srcIp.equals(dstIp)) {
508 dstIp = osNetService.gatewayIp(srcInstancePort.portId());
509 requestStringBuilder.append(DL_DST)
510 .append(DEFAULT_GATEWAY_MAC_STR).append(COMMA);
511 } else if (!osNetService.ipPrefix(srcInstancePort.portId()).contains(IpAddress.valueOf(dstIp))) {
512 requestStringBuilder.append(DL_DST)
513 .append(DEFAULT_GATEWAY_MAC_STR)
514 .append(COMMA);
515 }
516 } else {
517 if (srcIp.equals(dstIp)) {
518 dstIp = osNetService.gatewayIp(srcInstancePort.portId());
519 }
520 }
521
522 requestStringBuilder.append(NW_DST)
523 .append(dstIp)
524 .append("\n");
525 } else {
526 requestStringBuilder.append(COMMA)
527 .append(NW_SRC)
528 .append(dstIp)
529 .append(COMMA);
530
531 if (osNetService.networkType(srcInstancePort.networkId()).equals(VXLAN) ||
532 osNetService.networkType(srcInstancePort.networkId()).equals(VLAN)) {
533 requestStringBuilder.append(TUN_ID)
534 .append(osNetService.segmentId(srcInstancePort.networkId()))
535 .append(COMMA);
536 }
537 requestStringBuilder.append(NW_DST)
538 .append(srcIp)
539 .append("\n");
540
541 }
542
543 return requestStringBuilder.toString();
544 }
545
546 private String sendTraceRequestToNode(String requestString,
547 OpenstackNode node) {
Daniel Park577b69c2018-07-16 17:29:34 +0900548 String traceResult = null;
Daniel Park4e037f52018-09-20 18:04:18 +0900549 OpenstackSshAuth sshAuth = node.sshAuthInfo();
Daniel Park577b69c2018-07-16 17:29:34 +0900550
551 try (SshClient client = SshClient.setUpDefaultClient()) {
552 client.start();
553
554 try (ClientSession session = client
Daniel Park4e037f52018-09-20 18:04:18 +0900555 .connect(sshAuth.id(), node.managementIp().getIp4Address().toString(), SSH_PORT)
Daniel Park577b69c2018-07-16 17:29:34 +0900556 .verify(TIMEOUT_MS, TimeUnit.SECONDS).getSession()) {
557 session.addPasswordIdentity(sshAuth.password());
558 session.auth().verify(TIMEOUT_MS, TimeUnit.SECONDS);
559
560
561 try (ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) {
562
Daniel Park577b69c2018-07-16 17:29:34 +0900563 log.debug("requestString: {}", requestString);
564 final InputStream inputStream =
565 new ByteArrayInputStream(requestString.getBytes());
566
567 OutputStream outputStream = new ByteArrayOutputStream();
568 OutputStream errStream = new ByteArrayOutputStream();
569
570 channel.setIn(new NoCloseInputStream(inputStream));
571 channel.setErr(errStream);
572 channel.setOut(outputStream);
573
574 Collection<ClientChannelEvent> eventList = Lists.newArrayList();
575 eventList.add(ClientChannelEvent.OPENED);
576
577 OpenFuture channelFuture = channel.open();
578
579 if (channelFuture.await(TIMEOUT_MS, TimeUnit.SECONDS)) {
580
581 long timeoutExpiredMs = System.currentTimeMillis() + TIMEOUT_MS;
582
583 while (!channelFuture.isOpened()) {
584 if ((timeoutExpiredMs - System.currentTimeMillis()) <= 0) {
585 log.error("Failed to open channel");
586 return null;
587 }
588 }
589 TimeUnit.SECONDS.sleep(WAIT_OUTPUT_STREAM_SECOND);
590
591 traceResult = ((ByteArrayOutputStream) outputStream).toString(Charsets.UTF_8.name());
592
593 channel.close();
594 }
595 } finally {
596 session.close();
597 }
598 } finally {
599 client.stop();
600 }
601
602 } catch (Exception e) {
603 log.error("Exception occurred because of {}", e.toString());
604 }
605
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900606 return traceResult;
Daniel Park577b69c2018-07-16 17:29:34 +0900607 }
daniel park128c52c2017-09-04 13:15:51 +0900608}