blob: bfb18c8c5ffc912801bf6b5fdec3d6afcc540e23 [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;
Jian Li621f73c2018-12-15 01:49:22 +090046import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
Daniel Park577b69c2018-07-16 17:29:34 +090047import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
48import org.onosproject.openstacknode.api.OpenstackNode;
49import org.onosproject.openstacknode.api.OpenstackNodeService;
50import org.onosproject.openstacknode.api.OpenstackSshAuth;
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;
Jian Li621f73c2018-12-15 01:49:22 +090078import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GENEVE;
SONA Project6bc5c4a2018-12-14 23:49:52 +090079import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
80import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
81import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
daniel park128c52c2017-09-04 13:15:51 +090082
83/**
84 * OpenStack Networking UI message handler.
85 */
86public class OpenstackNetworkingUiMessageHandler extends UiMessageHandler {
87
88 private static final String OPENSTACK_NETWORKING_UI_START = "openstackNetworkingUiStart";
89 private static final String OPENSTACK_NETWORKING_UI_UPDATE = "openstackNetworkingUiUpdate";
90 private static final String OPENSTACK_NETWORKING_UI_STOP = "openstackNetworkingUiStop";
91 private static final String ANNOTATION_NETWORK_ID = "networkId";
92 private static final String FLOW_TRACE_REQUEST = "flowTraceRequest";
93 private static final String SRC_IP = "srcIp";
94 private static final String DST_IP = "dstIp";
95 private static final String ANNOTATION_SEGMENT_ID = "segId";
daniel park128c52c2017-09-04 13:15:51 +090096
97 private static final String ID = "id";
98 private static final String MODE = "mode";
99 private static final String MOUSE = "mouse";
Daniel Park577b69c2018-07-16 17:29:34 +0900100 private static final String TRACE_RESULT = "traceResult";
101 private static final String IS_SUCCESS = "isSuccess";
102 private static final String TRACE_SUCCESS = "traceSuccess";
103 private static final String FLOW_TRACE_RESULT = "flowTraceResult";
104 private static final String SRC_DEVICE_ID = "srcDeviceId";
105 private static final String DST_DEVICE_ID = "dstDeviceId";
Daniel Park4e037f52018-09-20 18:04:18 +0900106 private static final String UPLINK = "uplink";
Daniel Park577b69c2018-07-16 17:29:34 +0900107 private static final String OVS_VERSION_2_8 = "2.8";
Daniel Park4e037f52018-09-20 18:04:18 +0900108 private static final String OVS_VERSION_2_7 = "2.7";
Daniel Park577b69c2018-07-16 17:29:34 +0900109 private static final String OVS_VERSION_2_6 = "2.6";
Daniel Park4e037f52018-09-20 18:04:18 +0900110
Daniel Park577b69c2018-07-16 17:29:34 +0900111 private static final String DL_DST = "dl_dst=";
112 private static final String NW_DST = "nw_dst=";
Daniel Park4e037f52018-09-20 18:04:18 +0900113 private static final String DEFAULT_REQUEST_STRING = "sudo ovs-appctl ofproto/trace br-int ip";
114 private static final String IN_PORT = "in_port=";
Daniel Park577b69c2018-07-16 17:29:34 +0900115 private static final String NW_SRC = "nw_src=";
116 private static final String COMMA = ",";
Daniel Park4e037f52018-09-20 18:04:18 +0900117 private static final String TUN_ID = "tun_id=";
Daniel Park577b69c2018-07-16 17:29:34 +0900118
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;
daniel park128c52c2017-09-04 13:15:51 +0900133 private Mode currentMode = Mode.IDLE;
134 private Element elementOfNote;
daniel park128c52c2017-09-04 13:15:51 +0900135
Daniel Park577b69c2018-07-16 17:29:34 +0900136 private final ExecutorService eventExecutor = newSingleThreadExecutor(
137 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
daniel park128c52c2017-09-04 13:15:51 +0900138
139 @Override
140 public void init(UiConnection connection, ServiceDirectory directory) {
141 super.init(connection, directory);
142 deviceService = directory.get(DeviceService.class);
143 hostService = directory.get(HostService.class);
144 pathService = directory.get(PathService.class);
Daniel Park577b69c2018-07-16 17:29:34 +0900145 osNodeService = directory.get(OpenstackNodeService.class);
146 instancePortService = directory.get(InstancePortService.class);
147 osNetService = directory.get(OpenstackNetworkService.class);
daniel park128c52c2017-09-04 13:15:51 +0900148 }
149
daniel park128c52c2017-09-04 13:15:51 +0900150 @Override
151 protected Collection<RequestHandler> createRequestHandlers() {
152 return ImmutableSet.of(
153 new DisplayStartHandler(),
154 new DisplayUpdateHandler(),
155 new DisplayStopHandler(),
156 new FlowTraceRequestHandler()
157 );
158 }
159
daniel park128c52c2017-09-04 13:15:51 +0900160 private final class DisplayStartHandler extends RequestHandler {
161
162 public DisplayStartHandler() {
163 super(OPENSTACK_NETWORKING_UI_START);
164 }
165
166 @Override
167 public void process(ObjectNode payload) {
168 String mode = string(payload, MODE);
169
170 log.debug("Start Display: mode [{}]", mode);
171 clearState();
172 clearForMode();
173
174 switch (mode) {
175 case MOUSE:
176 currentMode = Mode.MOUSE;
Jian Lib7873422018-08-18 22:34:39 +0900177 eventExecutor.execute(OpenstackNetworkingUiMessageHandler.this::sendMouseData);
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900178
daniel park128c52c2017-09-04 13:15:51 +0900179 break;
180
181 default:
182 currentMode = Mode.IDLE;
183 break;
184 }
185 }
186 }
187
188 private final class FlowTraceRequestHandler extends RequestHandler {
189 public FlowTraceRequestHandler() {
190 super(FLOW_TRACE_REQUEST);
191 }
192
193 @Override
194 public void process(ObjectNode payload) {
195 String srcIp = string(payload, SRC_IP);
196 String dstIp = string(payload, DST_IP);
Daniel Park577b69c2018-07-16 17:29:34 +0900197 String srcDeviceId = string(payload, SRC_DEVICE_ID);
198 String dstDeviceId = string(payload, DST_DEVICE_ID);
Daniel Park4e037f52018-09-20 18:04:18 +0900199 boolean uplink = bool(payload, UPLINK);
200 log.info("Flow trace request called with" +
201 "src IP: {}, dst IP: {}, src device ID: {}, dst device Id: {}, uplink: ",
Daniel Park577b69c2018-07-16 17:29:34 +0900202 srcIp,
203 dstIp,
204 srcDeviceId,
Daniel Park4e037f52018-09-20 18:04:18 +0900205 dstDeviceId,
206 uplink);
207 eventExecutor.execute(() -> processFlowTraceRequest(srcIp, dstIp, srcDeviceId, dstDeviceId, uplink));
daniel park128c52c2017-09-04 13:15:51 +0900208 }
209 }
210
daniel park128c52c2017-09-04 13:15:51 +0900211 private final class DisplayUpdateHandler extends RequestHandler {
212 public DisplayUpdateHandler() {
213 super(OPENSTACK_NETWORKING_UI_UPDATE);
214 }
215
216 @Override
217 public void process(ObjectNode payload) {
218 String id = string(payload, ID);
219 log.debug("Update Display: id [{}]", id);
220 if (!Strings.isNullOrEmpty(id)) {
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900221 eventExecutor.execute(() -> updateForMode(id));
daniel park128c52c2017-09-04 13:15:51 +0900222 } else {
Jian Lib7873422018-08-18 22:34:39 +0900223 eventExecutor.execute(OpenstackNetworkingUiMessageHandler.this::clearForMode);
daniel park128c52c2017-09-04 13:15:51 +0900224 }
225 }
226 }
227
228 private final class DisplayStopHandler extends RequestHandler {
229 public DisplayStopHandler() {
230 super(OPENSTACK_NETWORKING_UI_STOP);
231 }
232
233 @Override
234 public void process(ObjectNode payload) {
235 log.debug("Stop Display");
236 clearState();
237 clearForMode();
238 }
239 }
240
daniel park128c52c2017-09-04 13:15:51 +0900241 private void clearState() {
242 currentMode = Mode.IDLE;
243 elementOfNote = null;
244 }
245
246 private void updateForMode(String id) {
247
248 try {
249 HostId hid = HostId.hostId(id);
250 elementOfNote = hostService.getHost(hid);
251
252 } catch (Exception e) {
253 try {
254 DeviceId did = DeviceId.deviceId(id);
255 elementOfNote = deviceService.getDevice(did);
256
257 } catch (Exception e2) {
258 log.debug("Unable to process ID [{}]", id);
259 elementOfNote = null;
260 }
261 }
262
263 switch (currentMode) {
264 case MOUSE:
265 sendMouseData();
266 break;
267
268 default:
269 break;
270 }
271
272 }
273
274 private void clearForMode() {
275 sendHighlights(new Highlights());
276 }
277
278 private void sendHighlights(Highlights highlights) {
279 sendMessage(TopoJson.highlightsMessage(highlights));
280 }
281
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900282 /**
283 * Sends JSON-based message to UI.
284 * @param type type
285 * @param payload payload
286 */
daniel park128c52c2017-09-04 13:15:51 +0900287 public void sendMessagetoUi(String type, ObjectNode payload) {
288 sendMessage(JsonUtils.envelope(type, payload));
289 }
290
291 private int getVni(Host host) {
292 String vni = host.annotations().value(ANNOTATION_SEGMENT_ID);
293
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900294 return vni == null ? 0 : Integer.parseInt(vni);
daniel park128c52c2017-09-04 13:15:51 +0900295 }
296
297 private void sendMouseData() {
298 Highlights highlights = new Highlights();
299
Jian Lib7873422018-08-18 22:34:39 +0900300 if (elementOfNote instanceof Device) {
daniel park128c52c2017-09-04 13:15:51 +0900301 DeviceId deviceId = (DeviceId) elementOfNote.id();
302
303 List<OpenstackLink> edgeLinks = edgeLinks(deviceId);
304
Jian Lib7873422018-08-18 22:34:39 +0900305 edgeLinks.forEach(edgeLink ->
306 highlights.add(edgeLink.highlight(OpenstackLink.RequestType.DEVICE_SELECTED)));
daniel park128c52c2017-09-04 13:15:51 +0900307
308 hostService.getConnectedHosts(deviceId).forEach(host -> {
309 HostHighlight hostHighlight = new HostHighlight(host.id().toString());
310 hostHighlight.setBadge(createBadge(getVni(host)));
311 highlights.add(hostHighlight);
312 });
313
314 sendHighlights(highlights);
315
Jian Lib7873422018-08-18 22:34:39 +0900316 } else if (elementOfNote instanceof Host) {
daniel park128c52c2017-09-04 13:15:51 +0900317
318 HostId hostId = HostId.hostId(elementOfNote.id().toString());
319 if (!hostMadeFromOpenstack(hostId)) {
320 return;
321 }
322
323 List<OpenstackLink> openstackLinks = linksInSameNetwork(hostId);
324
Jian Lib7873422018-08-18 22:34:39 +0900325 openstackLinks.forEach(openstackLink ->
326 highlights.add(openstackLink.highlight(OpenstackLink.RequestType.HOST_SELECTED)));
daniel park128c52c2017-09-04 13:15:51 +0900327
328 hostHighlightsInSameNetwork(hostId).forEach(highlights::add);
329
330 sendHighlights(highlights);
331
332 }
333 }
334
335 private boolean hostMadeFromOpenstack(HostId hostId) {
Jian Lib7873422018-08-18 22:34:39 +0900336 return hostService.getHost(hostId).annotations().value(ANNOTATION_NETWORK_ID) != null;
daniel park128c52c2017-09-04 13:15:51 +0900337 }
338
339 private String networkId(HostId hostId) {
340 return hostService.getHost(hostId).annotations().value(ANNOTATION_NETWORK_ID);
341 }
342
343 private Set<HostHighlight> hostHighlightsInSameNetwork(HostId hostId) {
344
345 Set<HostHighlight> hostHighlights = Sets.newHashSet();
346 Streams.stream(hostService.getHosts())
347 .filter(host -> isHostInSameNetwork(host, networkId(hostId)))
348 .forEach(host -> {
349 HostHighlight hostHighlight = new HostHighlight(host.id().toString());
350 hostHighlight.setBadge(createBadge(getVni(host)));
351 hostHighlights.add(hostHighlight);
352 });
353
354 return hostHighlights;
355 }
356
357 private List<OpenstackLink> edgeLinks(DeviceId deviceId) {
358 OpenstackLinkMap openstackLinkMap = new OpenstackLinkMap();
359
360 hostService.getConnectedHosts(deviceId).forEach(host -> {
361 openstackLinkMap.add(createEdgeLink(host, true));
362 openstackLinkMap.add(createEdgeLink(host, false));
363 });
364
365 List<OpenstackLink> edgeLinks = Lists.newArrayList();
366
Jian Lib7873422018-08-18 22:34:39 +0900367 edgeLinks.addAll(openstackLinkMap.biLinks());
daniel park128c52c2017-09-04 13:15:51 +0900368
369 return edgeLinks;
370 }
371
372 private List<OpenstackLink> linksInSameNetwork(HostId hostId) {
373 OpenstackLinkMap linkMap = new OpenstackLinkMap();
374
375 Streams.stream(hostService.getHosts())
376 .filter(host -> isHostInSameNetwork(host, networkId(hostId)))
377 .forEach(host -> {
378 linkMap.add(createEdgeLink(host, true));
379 linkMap.add(createEdgeLink(host, false));
380
381 Set<Path> paths = pathService.getPaths(hostId,
382 host.id());
383
384 if (!paths.isEmpty()) {
385 paths.forEach(path -> path.links().forEach(linkMap::add));
386 }
387 });
388
389 List<OpenstackLink> openstackLinks = Lists.newArrayList();
390
Jian Lib7873422018-08-18 22:34:39 +0900391 openstackLinks.addAll(linkMap.biLinks());
daniel park128c52c2017-09-04 13:15:51 +0900392
393 return openstackLinks;
394 }
395
396 private boolean isHostInSameNetwork(Host host, String networkId) {
397 return hostService.getHost(host.id()).annotations()
398 .value(ANNOTATION_NETWORK_ID).equals(networkId);
399 }
400
401 private NodeBadge createBadge(int n) {
402 return NodeBadge.number(Status.INFO, n, "Openstack Node");
403 }
Daniel Park577b69c2018-07-16 17:29:34 +0900404
Daniel Park4e037f52018-09-20 18:04:18 +0900405 private void processFlowTraceRequest(String srcIp, String dstIp, String srcDeviceId, String dstDeviceId,
406 boolean uplink) {
Daniel Park577b69c2018-07-16 17:29:34 +0900407 boolean traceSuccess = true;
408
409 ObjectMapper mapper = new ObjectMapper();
410
411 ObjectNode traceResult = mapper.createObjectNode();
412
413 ArrayNode traceResultArray = traceResult.putArray(TRACE_RESULT);
414
415 OpenstackNode srcOpenstackNode = osNodeService.node(DeviceId.deviceId(srcDeviceId));
416 if (srcOpenstackNode == null) {
Daniel Park4e037f52018-09-20 18:04:18 +0900417 log.error("There's no openstack node information for device {}", srcDeviceId);
Daniel Park577b69c2018-07-16 17:29:34 +0900418 return;
419 }
420
421 if (srcOpenstackNode.sshAuthInfo() == null) {
422 log.error("Openstack node {} has no SSH authentication information..",
423 srcOpenstackNode.hostname());
424 return;
425 }
426
Daniel Park4e037f52018-09-20 18:04:18 +0900427 String traceResultString = sendTraceRequestToNode(srcIp, dstIp, srcOpenstackNode, uplink);
428
429 if (traceResultString == null) {
Daniel Park577b69c2018-07-16 17:29:34 +0900430 return;
431 }
432
Daniel Park4e037f52018-09-20 18:04:18 +0900433 log.debug("traceResultString raw data: {}", traceResultString);
Daniel Park577b69c2018-07-16 17:29:34 +0900434
Daniel Park4e037f52018-09-20 18:04:18 +0900435 ObjectNode traceResultJson = null;
Daniel Park577b69c2018-07-16 17:29:34 +0900436
437 Device srcDevice = deviceService.getDevice(srcOpenstackNode.intgBridge());
Daniel Park4e037f52018-09-20 18:04:18 +0900438 if (srcDevice.swVersion().startsWith(OVS_VERSION_2_8) ||
439 srcDevice.swVersion().startsWith(OVS_VERSION_2_7)) {
440 traceResultJson = Ovs28FlowTraceResultParser.flowTraceResultInJson(
441 traceResultString.trim(), srcOpenstackNode.hostname());
Daniel Park577b69c2018-07-16 17:29:34 +0900442 } else {
443 log.error("Currently OVS version {} is not supported",
444 deviceService.getDevice(srcOpenstackNode.intgBridge()));
445 }
446
Daniel Park4e037f52018-09-20 18:04:18 +0900447 if (traceResultJson == null) {
Daniel Park577b69c2018-07-16 17:29:34 +0900448 return;
449 }
450
Daniel Park4e037f52018-09-20 18:04:18 +0900451 traceResultArray.add(traceResultJson);
Daniel Park577b69c2018-07-16 17:29:34 +0900452
Daniel Park4e037f52018-09-20 18:04:18 +0900453 log.debug("traceResultForward Json: {}", traceResultJson);
Daniel Park577b69c2018-07-16 17:29:34 +0900454
Daniel Park4e037f52018-09-20 18:04:18 +0900455 if (!traceResultJson.get(IS_SUCCESS).asBoolean()) {
Daniel Park577b69c2018-07-16 17:29:34 +0900456 traceSuccess = false;
457 }
458
Daniel Park577b69c2018-07-16 17:29:34 +0900459 traceResult.put(TRACE_SUCCESS, traceSuccess);
Daniel Park4e037f52018-09-20 18:04:18 +0900460
461 traceResult.put(SRC_IP, srcIp);
462 traceResult.put(DST_IP, dstIp);
463 traceResult.put(SRC_DEVICE_ID, srcDeviceId);
464 traceResult.put(DST_DEVICE_ID, dstDeviceId);
465 traceResult.put(UPLINK, uplink);
466
Daniel Park577b69c2018-07-16 17:29:34 +0900467 log.debug("traceResult Json: {}", traceResult);
468
469 sendMessagetoUi(FLOW_TRACE_RESULT, traceResult);
470
471 }
472
SONA Project6bc5c4a2018-12-14 23:49:52 +0900473 private String sendTraceRequestToNode(String srcIp, String dstIp,
474 OpenstackNode openstackNode, boolean uplink) {
Daniel Park4e037f52018-09-20 18:04:18 +0900475
476 Optional<InstancePort> instancePort = instancePortService.instancePorts().stream()
477 .filter(port -> port.ipAddress().getIp4Address().toString().equals(srcIp)
478 && port.deviceId().equals(openstackNode.intgBridge()))
479 .findAny();
480
481 if (!instancePort.isPresent()) {
482 return null;
483 }
484
485 String requestString = traceRequestString(srcIp, dstIp,
486 instancePort.get(), osNetService, uplink);
487
488 return sendTraceRequestToNode(requestString, openstackNode);
489 }
490
491 private String traceRequestString(String srcIp,
492 String dstIp,
493 InstancePort srcInstancePort,
494 OpenstackNetworkService osNetService,
495 boolean uplink) {
496
497 StringBuilder requestStringBuilder = new StringBuilder(DEFAULT_REQUEST_STRING);
498
499 if (uplink) {
500
501 requestStringBuilder.append(COMMA)
502 .append(IN_PORT)
503 .append(srcInstancePort.portNumber().toString())
504 .append(COMMA)
505 .append(NW_SRC)
506 .append(srcIp)
507 .append(COMMA);
508
Jian Li621f73c2018-12-15 01:49:22 +0900509 Type netType = osNetService.networkType(srcInstancePort.networkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900510
Jian Li621f73c2018-12-15 01:49:22 +0900511 if (netType == VXLAN || netType == VLAN || netType == GRE || netType == GENEVE) {
Daniel Park4e037f52018-09-20 18:04:18 +0900512 if (srcIp.equals(dstIp)) {
513 dstIp = osNetService.gatewayIp(srcInstancePort.portId());
514 requestStringBuilder.append(DL_DST)
515 .append(DEFAULT_GATEWAY_MAC_STR).append(COMMA);
516 } else if (!osNetService.ipPrefix(srcInstancePort.portId()).contains(IpAddress.valueOf(dstIp))) {
517 requestStringBuilder.append(DL_DST)
518 .append(DEFAULT_GATEWAY_MAC_STR)
519 .append(COMMA);
520 }
521 } else {
522 if (srcIp.equals(dstIp)) {
523 dstIp = osNetService.gatewayIp(srcInstancePort.portId());
524 }
525 }
526
527 requestStringBuilder.append(NW_DST)
528 .append(dstIp)
529 .append("\n");
530 } else {
531 requestStringBuilder.append(COMMA)
532 .append(NW_SRC)
533 .append(dstIp)
534 .append(COMMA);
535
536 if (osNetService.networkType(srcInstancePort.networkId()).equals(VXLAN) ||
537 osNetService.networkType(srcInstancePort.networkId()).equals(VLAN)) {
538 requestStringBuilder.append(TUN_ID)
539 .append(osNetService.segmentId(srcInstancePort.networkId()))
540 .append(COMMA);
541 }
542 requestStringBuilder.append(NW_DST)
543 .append(srcIp)
544 .append("\n");
545
546 }
547
548 return requestStringBuilder.toString();
549 }
550
551 private String sendTraceRequestToNode(String requestString,
552 OpenstackNode node) {
Daniel Park577b69c2018-07-16 17:29:34 +0900553 String traceResult = null;
Daniel Park4e037f52018-09-20 18:04:18 +0900554 OpenstackSshAuth sshAuth = node.sshAuthInfo();
Daniel Park577b69c2018-07-16 17:29:34 +0900555
556 try (SshClient client = SshClient.setUpDefaultClient()) {
557 client.start();
558
559 try (ClientSession session = client
Daniel Park4e037f52018-09-20 18:04:18 +0900560 .connect(sshAuth.id(), node.managementIp().getIp4Address().toString(), SSH_PORT)
Daniel Park577b69c2018-07-16 17:29:34 +0900561 .verify(TIMEOUT_MS, TimeUnit.SECONDS).getSession()) {
562 session.addPasswordIdentity(sshAuth.password());
563 session.auth().verify(TIMEOUT_MS, TimeUnit.SECONDS);
564
565
566 try (ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) {
567
Daniel Park577b69c2018-07-16 17:29:34 +0900568 log.debug("requestString: {}", requestString);
569 final InputStream inputStream =
570 new ByteArrayInputStream(requestString.getBytes());
571
572 OutputStream outputStream = new ByteArrayOutputStream();
573 OutputStream errStream = new ByteArrayOutputStream();
574
575 channel.setIn(new NoCloseInputStream(inputStream));
576 channel.setErr(errStream);
577 channel.setOut(outputStream);
578
579 Collection<ClientChannelEvent> eventList = Lists.newArrayList();
580 eventList.add(ClientChannelEvent.OPENED);
581
582 OpenFuture channelFuture = channel.open();
583
584 if (channelFuture.await(TIMEOUT_MS, TimeUnit.SECONDS)) {
585
586 long timeoutExpiredMs = System.currentTimeMillis() + TIMEOUT_MS;
587
588 while (!channelFuture.isOpened()) {
589 if ((timeoutExpiredMs - System.currentTimeMillis()) <= 0) {
590 log.error("Failed to open channel");
591 return null;
592 }
593 }
594 TimeUnit.SECONDS.sleep(WAIT_OUTPUT_STREAM_SECOND);
595
596 traceResult = ((ByteArrayOutputStream) outputStream).toString(Charsets.UTF_8.name());
597
598 channel.close();
599 }
600 } finally {
601 session.close();
602 }
603 } finally {
604 client.stop();
605 }
606
607 } catch (Exception e) {
608 log.error("Exception occurred because of {}", e.toString());
609 }
610
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900611 return traceResult;
Daniel Park577b69c2018-07-16 17:29:34 +0900612 }
daniel park128c52c2017-09-04 13:15:51 +0900613}