blob: c49944df3e728c74ebec012d0672a0c9d89db030 [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;
boyoung27b444122018-09-01 17:28:13 +090050import org.onosproject.openstacktelemetry.api.StatsFlowRuleAdminService;
daniel park128c52c2017-09-04 13:15:51 +090051import org.onosproject.ui.JsonUtils;
52import org.onosproject.ui.RequestHandler;
53import org.onosproject.ui.UiConnection;
54import org.onosproject.ui.UiMessageHandler;
daniel park128c52c2017-09-04 13:15:51 +090055import org.onosproject.ui.topo.Highlights;
56import org.onosproject.ui.topo.HostHighlight;
57import org.onosproject.ui.topo.NodeBadge;
58import org.onosproject.ui.topo.NodeBadge.Status;
59import org.onosproject.ui.topo.TopoJson;
60import org.slf4j.Logger;
61import org.slf4j.LoggerFactory;
62
daniel park128c52c2017-09-04 13:15:51 +090063import java.io.ByteArrayInputStream;
Daniel Park577b69c2018-07-16 17:29:34 +090064import java.io.ByteArrayOutputStream;
daniel park128c52c2017-09-04 13:15:51 +090065import java.io.InputStream;
Daniel Park577b69c2018-07-16 17:29:34 +090066import java.io.OutputStream;
daniel park128c52c2017-09-04 13:15:51 +090067import java.util.Collection;
68import java.util.List;
Daniel Park577b69c2018-07-16 17:29:34 +090069import java.util.Optional;
daniel park128c52c2017-09-04 13:15:51 +090070import java.util.Set;
Daniel Park577b69c2018-07-16 17:29:34 +090071import java.util.concurrent.ExecutorService;
72import java.util.concurrent.TimeUnit;
daniel park128c52c2017-09-04 13:15:51 +090073
Daniel Park577b69c2018-07-16 17:29:34 +090074import static java.util.concurrent.Executors.newSingleThreadExecutor;
75import static org.onlab.util.Tools.groupedThreads;
daniel park128c52c2017-09-04 13:15:51 +090076import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
Daniel Park577b69c2018-07-16 17:29:34 +090077import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
daniel park128c52c2017-09-04 13:15:51 +090078
79/**
80 * OpenStack Networking UI message handler.
81 */
82public class OpenstackNetworkingUiMessageHandler extends UiMessageHandler {
83
84 private static final String OPENSTACK_NETWORKING_UI_START = "openstackNetworkingUiStart";
85 private static final String OPENSTACK_NETWORKING_UI_UPDATE = "openstackNetworkingUiUpdate";
86 private static final String OPENSTACK_NETWORKING_UI_STOP = "openstackNetworkingUiStop";
87 private static final String ANNOTATION_NETWORK_ID = "networkId";
boyoung27b444122018-09-01 17:28:13 +090088 private static final String FLOW_STATS_ADD_REQUEST = "flowStatsAddRequest";
89 private static final String FLOW_STATS_REMOVE_REQUEST = "flowStatsRemoveRequest";
daniel park128c52c2017-09-04 13:15:51 +090090 private static final String FLOW_TRACE_REQUEST = "flowTraceRequest";
91 private static final String SRC_IP = "srcIp";
92 private static final String DST_IP = "dstIp";
93 private static final String ANNOTATION_SEGMENT_ID = "segId";
daniel park128c52c2017-09-04 13:15:51 +090094
95 private static final String ID = "id";
96 private static final String MODE = "mode";
97 private static final String MOUSE = "mouse";
Daniel Park577b69c2018-07-16 17:29:34 +090098 private static final String TRACE_RESULT = "traceResult";
99 private static final String IS_SUCCESS = "isSuccess";
100 private static final String TRACE_SUCCESS = "traceSuccess";
boyoung27b444122018-09-01 17:28:13 +0900101 private static final String STATS_SUCCESS = "statsSuccess";
102 private static final String FLOW_STATS_ADD_RESULT = "flowStatsAddResult";
103 private static final String FLOW_STATS_REMOVE_RESULT = "flowStatsRemoveResult";
Daniel Park577b69c2018-07-16 17:29:34 +0900104 private static final String FLOW_TRACE_RESULT = "flowTraceResult";
105 private static final String SRC_DEVICE_ID = "srcDeviceId";
106 private static final String DST_DEVICE_ID = "dstDeviceId";
Daniel Park577b69c2018-07-16 17:29:34 +0900107 private static final String OVS_VERSION_2_8 = "2.8";
108 private static final String OVS_VERSION_2_6 = "2.6";
109 private static final String FLAT = "FLAT";
110 private static final String VXLAN = "VXLAN";
111 private static final String VLAN = "VLAN";
112 private static final String DL_DST = "dl_dst=";
113 private static final String NW_DST = "nw_dst=";
114 private static final String DEFAULT_REQUEST_STRING = "sudo ovs-appctl ofproto/trace br-int ip,in_port=";
115 private static final String NW_SRC = "nw_src=";
116 private static final String COMMA = ",";
117
118
119 private static final long TIMEOUT_MS = 5000;
120 private static final long WAIT_OUTPUT_STREAM_SECOND = 2;
121 private static final int SSH_PORT = 22;
daniel park128c52c2017-09-04 13:15:51 +0900122
123 private enum Mode { IDLE, MOUSE }
124
125 private final Logger log = LoggerFactory.getLogger(getClass());
126
127 private DeviceService deviceService;
128 private HostService hostService;
129 private PathService pathService;
Daniel Park577b69c2018-07-16 17:29:34 +0900130 private OpenstackNodeService osNodeService;
131 private InstancePortService instancePortService;
132 private OpenstackNetworkService osNetService;
boyoung27b444122018-09-01 17:28:13 +0900133 private StatsFlowRuleAdminService statsFlowRuleService;
daniel park128c52c2017-09-04 13:15:51 +0900134 private Mode currentMode = Mode.IDLE;
135 private Element elementOfNote;
daniel park128c52c2017-09-04 13:15:51 +0900136
Daniel Park577b69c2018-07-16 17:29:34 +0900137 private final ExecutorService eventExecutor = newSingleThreadExecutor(
138 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
daniel park128c52c2017-09-04 13:15:51 +0900139
140 @Override
141 public void init(UiConnection connection, ServiceDirectory directory) {
142 super.init(connection, directory);
143 deviceService = directory.get(DeviceService.class);
144 hostService = directory.get(HostService.class);
145 pathService = directory.get(PathService.class);
Daniel Park577b69c2018-07-16 17:29:34 +0900146 osNodeService = directory.get(OpenstackNodeService.class);
147 instancePortService = directory.get(InstancePortService.class);
148 osNetService = directory.get(OpenstackNetworkService.class);
boyoung27b444122018-09-01 17:28:13 +0900149 statsFlowRuleService = directory.get(StatsFlowRuleAdminService.class);
daniel park128c52c2017-09-04 13:15:51 +0900150 }
151
daniel park128c52c2017-09-04 13:15:51 +0900152 @Override
153 protected Collection<RequestHandler> createRequestHandlers() {
154 return ImmutableSet.of(
155 new DisplayStartHandler(),
156 new DisplayUpdateHandler(),
157 new DisplayStopHandler(),
boyoung27b444122018-09-01 17:28:13 +0900158 new FlowStatsAddRequestHandler(),
159 new FlowStatsRemoveRequestHandler(),
daniel park128c52c2017-09-04 13:15:51 +0900160 new FlowTraceRequestHandler()
161 );
162 }
163
daniel park128c52c2017-09-04 13:15:51 +0900164 private final class DisplayStartHandler extends RequestHandler {
165
166 public DisplayStartHandler() {
167 super(OPENSTACK_NETWORKING_UI_START);
168 }
169
170 @Override
171 public void process(ObjectNode payload) {
172 String mode = string(payload, MODE);
173
174 log.debug("Start Display: mode [{}]", mode);
175 clearState();
176 clearForMode();
177
178 switch (mode) {
179 case MOUSE:
180 currentMode = Mode.MOUSE;
Jian Lib7873422018-08-18 22:34:39 +0900181 eventExecutor.execute(OpenstackNetworkingUiMessageHandler.this::sendMouseData);
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900182
daniel park128c52c2017-09-04 13:15:51 +0900183 break;
184
185 default:
186 currentMode = Mode.IDLE;
187 break;
188 }
189 }
190 }
191
boyoung27b444122018-09-01 17:28:13 +0900192 private final class FlowStatsAddRequestHandler extends RequestHandler {
193 public FlowStatsAddRequestHandler() {
194 super(FLOW_STATS_ADD_REQUEST);
195 }
196
197 @Override
198 public void process(ObjectNode payload) {
199 String srcIp = string(payload, SRC_IP);
200 String dstIp = string(payload, DST_IP);
201 log.info("Flow statistics add request called with src IP: {}, dst IP: {}",
202 srcIp, dstIp);
203 eventExecutor.execute(() -> processFlowStatsRequest(srcIp, dstIp, true));
204 }
205 }
206
207 private final class FlowStatsRemoveRequestHandler extends RequestHandler {
208 public FlowStatsRemoveRequestHandler() {
209 super(FLOW_STATS_REMOVE_REQUEST);
210 }
211
212 @Override
213 public void process(ObjectNode payload) {
214 String srcIp = string(payload, SRC_IP);
215 String dstIp = string(payload, DST_IP);
216 log.info("Flow statistics removal request called with src IP: {}, dst IP: {}",
217 srcIp, dstIp);
218 eventExecutor.execute(() -> processFlowStatsRequest(srcIp, dstIp, false));
219 }
220 }
221
daniel park128c52c2017-09-04 13:15:51 +0900222 private final class FlowTraceRequestHandler extends RequestHandler {
223 public FlowTraceRequestHandler() {
224 super(FLOW_TRACE_REQUEST);
225 }
226
227 @Override
228 public void process(ObjectNode payload) {
229 String srcIp = string(payload, SRC_IP);
230 String dstIp = string(payload, DST_IP);
Daniel Park577b69c2018-07-16 17:29:34 +0900231 String srcDeviceId = string(payload, SRC_DEVICE_ID);
232 String dstDeviceId = string(payload, DST_DEVICE_ID);
233 log.info("Flow trace request called with src IP: {}, dst IP: {}, src device ID: {}, dst device Id: {}",
234 srcIp,
235 dstIp,
236 srcDeviceId,
237 dstDeviceId);
Jian Lib7873422018-08-18 22:34:39 +0900238 eventExecutor.execute(() -> processFlowTraceRequest(srcIp, dstIp, srcDeviceId));
daniel park128c52c2017-09-04 13:15:51 +0900239 }
240 }
241
daniel park128c52c2017-09-04 13:15:51 +0900242 private final class DisplayUpdateHandler extends RequestHandler {
243 public DisplayUpdateHandler() {
244 super(OPENSTACK_NETWORKING_UI_UPDATE);
245 }
246
247 @Override
248 public void process(ObjectNode payload) {
249 String id = string(payload, ID);
250 log.debug("Update Display: id [{}]", id);
251 if (!Strings.isNullOrEmpty(id)) {
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900252 eventExecutor.execute(() -> updateForMode(id));
daniel park128c52c2017-09-04 13:15:51 +0900253 } else {
Jian Lib7873422018-08-18 22:34:39 +0900254 eventExecutor.execute(OpenstackNetworkingUiMessageHandler.this::clearForMode);
daniel park128c52c2017-09-04 13:15:51 +0900255 }
256 }
257 }
258
259 private final class DisplayStopHandler extends RequestHandler {
260 public DisplayStopHandler() {
261 super(OPENSTACK_NETWORKING_UI_STOP);
262 }
263
264 @Override
265 public void process(ObjectNode payload) {
266 log.debug("Stop Display");
267 clearState();
268 clearForMode();
269 }
270 }
271
daniel park128c52c2017-09-04 13:15:51 +0900272 private void clearState() {
273 currentMode = Mode.IDLE;
274 elementOfNote = null;
275 }
276
277 private void updateForMode(String id) {
278
279 try {
280 HostId hid = HostId.hostId(id);
281 elementOfNote = hostService.getHost(hid);
282
283 } catch (Exception e) {
284 try {
285 DeviceId did = DeviceId.deviceId(id);
286 elementOfNote = deviceService.getDevice(did);
287
288 } catch (Exception e2) {
289 log.debug("Unable to process ID [{}]", id);
290 elementOfNote = null;
291 }
292 }
293
294 switch (currentMode) {
295 case MOUSE:
296 sendMouseData();
297 break;
298
299 default:
300 break;
301 }
302
303 }
304
305 private void clearForMode() {
306 sendHighlights(new Highlights());
307 }
308
309 private void sendHighlights(Highlights highlights) {
310 sendMessage(TopoJson.highlightsMessage(highlights));
311 }
312
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900313 /**
314 * Sends JSON-based message to UI.
315 * @param type type
316 * @param payload payload
317 */
daniel park128c52c2017-09-04 13:15:51 +0900318 public void sendMessagetoUi(String type, ObjectNode payload) {
319 sendMessage(JsonUtils.envelope(type, payload));
320 }
321
322 private int getVni(Host host) {
323 String vni = host.annotations().value(ANNOTATION_SEGMENT_ID);
324
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900325 return vni == null ? 0 : Integer.parseInt(vni);
daniel park128c52c2017-09-04 13:15:51 +0900326 }
327
328 private void sendMouseData() {
329 Highlights highlights = new Highlights();
330
Jian Lib7873422018-08-18 22:34:39 +0900331 if (elementOfNote instanceof Device) {
daniel park128c52c2017-09-04 13:15:51 +0900332 DeviceId deviceId = (DeviceId) elementOfNote.id();
333
334 List<OpenstackLink> edgeLinks = edgeLinks(deviceId);
335
Jian Lib7873422018-08-18 22:34:39 +0900336 edgeLinks.forEach(edgeLink ->
337 highlights.add(edgeLink.highlight(OpenstackLink.RequestType.DEVICE_SELECTED)));
daniel park128c52c2017-09-04 13:15:51 +0900338
339 hostService.getConnectedHosts(deviceId).forEach(host -> {
340 HostHighlight hostHighlight = new HostHighlight(host.id().toString());
341 hostHighlight.setBadge(createBadge(getVni(host)));
342 highlights.add(hostHighlight);
343 });
344
345 sendHighlights(highlights);
346
Jian Lib7873422018-08-18 22:34:39 +0900347 } else if (elementOfNote instanceof Host) {
daniel park128c52c2017-09-04 13:15:51 +0900348
349 HostId hostId = HostId.hostId(elementOfNote.id().toString());
350 if (!hostMadeFromOpenstack(hostId)) {
351 return;
352 }
353
354 List<OpenstackLink> openstackLinks = linksInSameNetwork(hostId);
355
Jian Lib7873422018-08-18 22:34:39 +0900356 openstackLinks.forEach(openstackLink ->
357 highlights.add(openstackLink.highlight(OpenstackLink.RequestType.HOST_SELECTED)));
daniel park128c52c2017-09-04 13:15:51 +0900358
359 hostHighlightsInSameNetwork(hostId).forEach(highlights::add);
360
361 sendHighlights(highlights);
362
363 }
364 }
365
366 private boolean hostMadeFromOpenstack(HostId hostId) {
Jian Lib7873422018-08-18 22:34:39 +0900367 return hostService.getHost(hostId).annotations().value(ANNOTATION_NETWORK_ID) != null;
daniel park128c52c2017-09-04 13:15:51 +0900368 }
369
370 private String networkId(HostId hostId) {
371 return hostService.getHost(hostId).annotations().value(ANNOTATION_NETWORK_ID);
372 }
373
374 private Set<HostHighlight> hostHighlightsInSameNetwork(HostId hostId) {
375
376 Set<HostHighlight> hostHighlights = Sets.newHashSet();
377 Streams.stream(hostService.getHosts())
378 .filter(host -> isHostInSameNetwork(host, networkId(hostId)))
379 .forEach(host -> {
380 HostHighlight hostHighlight = new HostHighlight(host.id().toString());
381 hostHighlight.setBadge(createBadge(getVni(host)));
382 hostHighlights.add(hostHighlight);
383 });
384
385 return hostHighlights;
386 }
387
388 private List<OpenstackLink> edgeLinks(DeviceId deviceId) {
389 OpenstackLinkMap openstackLinkMap = new OpenstackLinkMap();
390
391 hostService.getConnectedHosts(deviceId).forEach(host -> {
392 openstackLinkMap.add(createEdgeLink(host, true));
393 openstackLinkMap.add(createEdgeLink(host, false));
394 });
395
396 List<OpenstackLink> edgeLinks = Lists.newArrayList();
397
Jian Lib7873422018-08-18 22:34:39 +0900398 edgeLinks.addAll(openstackLinkMap.biLinks());
daniel park128c52c2017-09-04 13:15:51 +0900399
400 return edgeLinks;
401 }
402
403 private List<OpenstackLink> linksInSameNetwork(HostId hostId) {
404 OpenstackLinkMap linkMap = new OpenstackLinkMap();
405
406 Streams.stream(hostService.getHosts())
407 .filter(host -> isHostInSameNetwork(host, networkId(hostId)))
408 .forEach(host -> {
409 linkMap.add(createEdgeLink(host, true));
410 linkMap.add(createEdgeLink(host, false));
411
412 Set<Path> paths = pathService.getPaths(hostId,
413 host.id());
414
415 if (!paths.isEmpty()) {
416 paths.forEach(path -> path.links().forEach(linkMap::add));
417 }
418 });
419
420 List<OpenstackLink> openstackLinks = Lists.newArrayList();
421
Jian Lib7873422018-08-18 22:34:39 +0900422 openstackLinks.addAll(linkMap.biLinks());
daniel park128c52c2017-09-04 13:15:51 +0900423
424 return openstackLinks;
425 }
426
427 private boolean isHostInSameNetwork(Host host, String networkId) {
428 return hostService.getHost(host.id()).annotations()
429 .value(ANNOTATION_NETWORK_ID).equals(networkId);
430 }
431
432 private NodeBadge createBadge(int n) {
433 return NodeBadge.number(Status.INFO, n, "Openstack Node");
434 }
Daniel Park577b69c2018-07-16 17:29:34 +0900435
boyoung27b444122018-09-01 17:28:13 +0900436 private void processFlowStatsRequest(String srcIp, String dstIp, Boolean install) {
437 boolean statsSuccess = true;
438 ObjectMapper mapper = new ObjectMapper();
439 ObjectNode statsResult = mapper.createObjectNode();
440
441 statsFlowRuleService.setStatFlowL2Rule(srcIp, dstIp, install);
442 statsResult.put(STATS_SUCCESS, statsSuccess);
443 sendMessagetoUi(FLOW_STATS_ADD_RESULT, statsResult);
444 }
445
Jian Lib7873422018-08-18 22:34:39 +0900446 private void processFlowTraceRequest(String srcIp, String dstIp, String srcDeviceId) {
Daniel Park577b69c2018-07-16 17:29:34 +0900447 boolean traceSuccess = true;
448
449 ObjectMapper mapper = new ObjectMapper();
450
451 ObjectNode traceResult = mapper.createObjectNode();
452
453 ArrayNode traceResultArray = traceResult.putArray(TRACE_RESULT);
454
455 OpenstackNode srcOpenstackNode = osNodeService.node(DeviceId.deviceId(srcDeviceId));
456 if (srcOpenstackNode == null) {
457 return;
458 }
459
460 if (srcOpenstackNode.sshAuthInfo() == null) {
461 log.error("Openstack node {} has no SSH authentication information..",
462 srcOpenstackNode.hostname());
463 return;
464 }
465
466 String traceResultForward = sendTraceRequestToNode(srcIp, dstIp, srcOpenstackNode);
467 if (traceResultForward == null) {
468 return;
469 }
470
471 log.debug("traceResultForward raw data: {}", traceResultForward);
472
473 ObjectNode traceResultForwardJson = null;
474
475 Device srcDevice = deviceService.getDevice(srcOpenstackNode.intgBridge());
Daniel Parke910e402018-07-26 11:25:01 +0900476 if (srcDevice.swVersion().startsWith(OVS_VERSION_2_8)) {
Daniel Park577b69c2018-07-16 17:29:34 +0900477 traceResultForwardJson = Ovs28FlowTraceResultParser.flowTraceResultInJson(
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900478 traceResultForward.trim(), srcOpenstackNode.hostname());
Daniel Park577b69c2018-07-16 17:29:34 +0900479 } else {
480 log.error("Currently OVS version {} is not supported",
481 deviceService.getDevice(srcOpenstackNode.intgBridge()));
482 }
483
484 if (traceResultForwardJson == null) {
485 return;
486 }
487
488 traceResultArray.add(traceResultForwardJson);
489
490 log.debug("traceResultForward Json: {}", traceResultForwardJson);
491
492 if (!traceResultForwardJson.get(IS_SUCCESS).asBoolean()) {
493 traceSuccess = false;
494 }
495
Daniel Park577b69c2018-07-16 17:29:34 +0900496 traceResult.put(TRACE_SUCCESS, traceSuccess);
497 log.debug("traceResult Json: {}", traceResult);
498
499 sendMessagetoUi(FLOW_TRACE_RESULT, traceResult);
500
501 }
502
503 private String sendTraceRequestToNode(String srcIp, String dstIp, OpenstackNode openstackNode) {
504 String traceResult = null;
505 OpenstackSshAuth sshAuth = openstackNode.sshAuthInfo();
506
507 try (SshClient client = SshClient.setUpDefaultClient()) {
508 client.start();
509
510 try (ClientSession session = client
511 .connect(sshAuth.id(), openstackNode.managementIp().getIp4Address().toString(), SSH_PORT)
512 .verify(TIMEOUT_MS, TimeUnit.SECONDS).getSession()) {
513 session.addPasswordIdentity(sshAuth.password());
514 session.auth().verify(TIMEOUT_MS, TimeUnit.SECONDS);
515
516
517 try (ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) {
518
519 String requestString = traceRequestString(srcIp, dstIp, openstackNode);
520 if (requestString == null) {
521 return null;
522 }
523
524 log.debug("requestString: {}", requestString);
525 final InputStream inputStream =
526 new ByteArrayInputStream(requestString.getBytes());
527
528 OutputStream outputStream = new ByteArrayOutputStream();
529 OutputStream errStream = new ByteArrayOutputStream();
530
531 channel.setIn(new NoCloseInputStream(inputStream));
532 channel.setErr(errStream);
533 channel.setOut(outputStream);
534
535 Collection<ClientChannelEvent> eventList = Lists.newArrayList();
536 eventList.add(ClientChannelEvent.OPENED);
537
538 OpenFuture channelFuture = channel.open();
539
540 if (channelFuture.await(TIMEOUT_MS, TimeUnit.SECONDS)) {
541
542 long timeoutExpiredMs = System.currentTimeMillis() + TIMEOUT_MS;
543
544 while (!channelFuture.isOpened()) {
545 if ((timeoutExpiredMs - System.currentTimeMillis()) <= 0) {
546 log.error("Failed to open channel");
547 return null;
548 }
549 }
550 TimeUnit.SECONDS.sleep(WAIT_OUTPUT_STREAM_SECOND);
551
552 traceResult = ((ByteArrayOutputStream) outputStream).toString(Charsets.UTF_8.name());
553
554 channel.close();
555 }
556 } finally {
557 session.close();
558 }
559 } finally {
560 client.stop();
561 }
562
563 } catch (Exception e) {
564 log.error("Exception occurred because of {}", e.toString());
565 }
566
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900567 return traceResult;
Daniel Park577b69c2018-07-16 17:29:34 +0900568 }
569
570 private String traceRequestString(String srcIp, String dstIp, OpenstackNode openstackNode) {
571
572 Optional<InstancePort> instancePort = instancePortService.instancePorts().stream()
573 .filter(port -> port.ipAddress().getIp4Address().toString().equals(srcIp)
574 && port.deviceId().equals(openstackNode.intgBridge()))
575 .findAny();
576
577 if (!instancePort.isPresent()) {
578 return null;
579 }
580
581 String requestString = DEFAULT_REQUEST_STRING
582 + instancePort.get().portNumber().toString()
583 + COMMA
584 + NW_SRC
585 + srcIp
586 + COMMA;
587
588 if (osNetService.networkType(instancePort.get().networkId()).equals(VXLAN)) {
589 if (srcIp.equals(dstIp)) {
590 dstIp = osNetService.gatewayIp(instancePort.get().portId());
591 requestString = requestString + DL_DST + DEFAULT_GATEWAY_MAC_STR + COMMA;
592 } else if (!osNetService.ipPrefix(instancePort.get().portId()).contains(IpAddress.valueOf(dstIp))) {
593 requestString = requestString + DL_DST + DEFAULT_GATEWAY_MAC_STR + COMMA;
594 }
595 } else if (osNetService.networkType(instancePort.get().networkId()).equals(FLAT)) {
596 if (srcIp.equals(dstIp)) {
597 dstIp = osNetService.gatewayIp(instancePort.get().portId());
598 }
599 }
600
601 requestString = requestString + NW_DST + dstIp + "\n";
602
603 return requestString;
604 }
daniel park128c52c2017-09-04 13:15:51 +0900605}