blob: 32964af592205094e6a51fcb3c3da84f0954254c [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 Park4e037f52018-09-20 18:04:18 +0900107 private static final String UPLINK = "uplink";
Daniel Park577b69c2018-07-16 17:29:34 +0900108 private static final String OVS_VERSION_2_8 = "2.8";
Daniel Park4e037f52018-09-20 18:04:18 +0900109 private static final String OVS_VERSION_2_7 = "2.7";
Daniel Park577b69c2018-07-16 17:29:34 +0900110 private static final String OVS_VERSION_2_6 = "2.6";
Daniel Park4e037f52018-09-20 18:04:18 +0900111
Daniel Park577b69c2018-07-16 17:29:34 +0900112 private static final String VXLAN = "VXLAN";
113 private static final String VLAN = "VLAN";
114 private static final String DL_DST = "dl_dst=";
115 private static final String NW_DST = "nw_dst=";
Daniel Park4e037f52018-09-20 18:04:18 +0900116 private static final String DEFAULT_REQUEST_STRING = "sudo ovs-appctl ofproto/trace br-int ip";
117 private static final String IN_PORT = "in_port=";
Daniel Park577b69c2018-07-16 17:29:34 +0900118 private static final String NW_SRC = "nw_src=";
119 private static final String COMMA = ",";
Daniel Park4e037f52018-09-20 18:04:18 +0900120 private static final String TUN_ID = "tun_id=";
Daniel Park577b69c2018-07-16 17:29:34 +0900121
122 private static final long TIMEOUT_MS = 5000;
123 private static final long WAIT_OUTPUT_STREAM_SECOND = 2;
124 private static final int SSH_PORT = 22;
daniel park128c52c2017-09-04 13:15:51 +0900125
126 private enum Mode { IDLE, MOUSE }
127
128 private final Logger log = LoggerFactory.getLogger(getClass());
129
130 private DeviceService deviceService;
131 private HostService hostService;
132 private PathService pathService;
Daniel Park577b69c2018-07-16 17:29:34 +0900133 private OpenstackNodeService osNodeService;
134 private InstancePortService instancePortService;
135 private OpenstackNetworkService osNetService;
boyoung27b444122018-09-01 17:28:13 +0900136 private StatsFlowRuleAdminService statsFlowRuleService;
daniel park128c52c2017-09-04 13:15:51 +0900137 private Mode currentMode = Mode.IDLE;
138 private Element elementOfNote;
daniel park128c52c2017-09-04 13:15:51 +0900139
Daniel Park577b69c2018-07-16 17:29:34 +0900140 private final ExecutorService eventExecutor = newSingleThreadExecutor(
141 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
daniel park128c52c2017-09-04 13:15:51 +0900142
143 @Override
144 public void init(UiConnection connection, ServiceDirectory directory) {
145 super.init(connection, directory);
146 deviceService = directory.get(DeviceService.class);
147 hostService = directory.get(HostService.class);
148 pathService = directory.get(PathService.class);
Daniel Park577b69c2018-07-16 17:29:34 +0900149 osNodeService = directory.get(OpenstackNodeService.class);
150 instancePortService = directory.get(InstancePortService.class);
151 osNetService = directory.get(OpenstackNetworkService.class);
boyoung27b444122018-09-01 17:28:13 +0900152 statsFlowRuleService = directory.get(StatsFlowRuleAdminService.class);
daniel park128c52c2017-09-04 13:15:51 +0900153 }
154
daniel park128c52c2017-09-04 13:15:51 +0900155 @Override
156 protected Collection<RequestHandler> createRequestHandlers() {
157 return ImmutableSet.of(
158 new DisplayStartHandler(),
159 new DisplayUpdateHandler(),
160 new DisplayStopHandler(),
boyoung27b444122018-09-01 17:28:13 +0900161 new FlowStatsAddRequestHandler(),
162 new FlowStatsRemoveRequestHandler(),
daniel park128c52c2017-09-04 13:15:51 +0900163 new FlowTraceRequestHandler()
164 );
165 }
166
daniel park128c52c2017-09-04 13:15:51 +0900167 private final class DisplayStartHandler extends RequestHandler {
168
169 public DisplayStartHandler() {
170 super(OPENSTACK_NETWORKING_UI_START);
171 }
172
173 @Override
174 public void process(ObjectNode payload) {
175 String mode = string(payload, MODE);
176
177 log.debug("Start Display: mode [{}]", mode);
178 clearState();
179 clearForMode();
180
181 switch (mode) {
182 case MOUSE:
183 currentMode = Mode.MOUSE;
Jian Lib7873422018-08-18 22:34:39 +0900184 eventExecutor.execute(OpenstackNetworkingUiMessageHandler.this::sendMouseData);
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900185
daniel park128c52c2017-09-04 13:15:51 +0900186 break;
187
188 default:
189 currentMode = Mode.IDLE;
190 break;
191 }
192 }
193 }
194
boyoung27b444122018-09-01 17:28:13 +0900195 private final class FlowStatsAddRequestHandler extends RequestHandler {
196 public FlowStatsAddRequestHandler() {
197 super(FLOW_STATS_ADD_REQUEST);
198 }
199
200 @Override
201 public void process(ObjectNode payload) {
202 String srcIp = string(payload, SRC_IP);
203 String dstIp = string(payload, DST_IP);
204 log.info("Flow statistics add request called with src IP: {}, dst IP: {}",
205 srcIp, dstIp);
206 eventExecutor.execute(() -> processFlowStatsRequest(srcIp, dstIp, true));
207 }
208 }
209
210 private final class FlowStatsRemoveRequestHandler extends RequestHandler {
211 public FlowStatsRemoveRequestHandler() {
212 super(FLOW_STATS_REMOVE_REQUEST);
213 }
214
215 @Override
216 public void process(ObjectNode payload) {
217 String srcIp = string(payload, SRC_IP);
218 String dstIp = string(payload, DST_IP);
219 log.info("Flow statistics removal request called with src IP: {}, dst IP: {}",
220 srcIp, dstIp);
221 eventExecutor.execute(() -> processFlowStatsRequest(srcIp, dstIp, false));
222 }
223 }
224
daniel park128c52c2017-09-04 13:15:51 +0900225 private final class FlowTraceRequestHandler extends RequestHandler {
226 public FlowTraceRequestHandler() {
227 super(FLOW_TRACE_REQUEST);
228 }
229
230 @Override
231 public void process(ObjectNode payload) {
232 String srcIp = string(payload, SRC_IP);
233 String dstIp = string(payload, DST_IP);
Daniel Park577b69c2018-07-16 17:29:34 +0900234 String srcDeviceId = string(payload, SRC_DEVICE_ID);
235 String dstDeviceId = string(payload, DST_DEVICE_ID);
Daniel Park4e037f52018-09-20 18:04:18 +0900236 boolean uplink = bool(payload, UPLINK);
237 log.info("Flow trace request called with" +
238 "src IP: {}, dst IP: {}, src device ID: {}, dst device Id: {}, uplink: ",
Daniel Park577b69c2018-07-16 17:29:34 +0900239 srcIp,
240 dstIp,
241 srcDeviceId,
Daniel Park4e037f52018-09-20 18:04:18 +0900242 dstDeviceId,
243 uplink);
244 eventExecutor.execute(() -> processFlowTraceRequest(srcIp, dstIp, srcDeviceId, dstDeviceId, uplink));
daniel park128c52c2017-09-04 13:15:51 +0900245 }
246 }
247
daniel park128c52c2017-09-04 13:15:51 +0900248 private final class DisplayUpdateHandler extends RequestHandler {
249 public DisplayUpdateHandler() {
250 super(OPENSTACK_NETWORKING_UI_UPDATE);
251 }
252
253 @Override
254 public void process(ObjectNode payload) {
255 String id = string(payload, ID);
256 log.debug("Update Display: id [{}]", id);
257 if (!Strings.isNullOrEmpty(id)) {
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900258 eventExecutor.execute(() -> updateForMode(id));
daniel park128c52c2017-09-04 13:15:51 +0900259 } else {
Jian Lib7873422018-08-18 22:34:39 +0900260 eventExecutor.execute(OpenstackNetworkingUiMessageHandler.this::clearForMode);
daniel park128c52c2017-09-04 13:15:51 +0900261 }
262 }
263 }
264
265 private final class DisplayStopHandler extends RequestHandler {
266 public DisplayStopHandler() {
267 super(OPENSTACK_NETWORKING_UI_STOP);
268 }
269
270 @Override
271 public void process(ObjectNode payload) {
272 log.debug("Stop Display");
273 clearState();
274 clearForMode();
275 }
276 }
277
daniel park128c52c2017-09-04 13:15:51 +0900278 private void clearState() {
279 currentMode = Mode.IDLE;
280 elementOfNote = null;
281 }
282
283 private void updateForMode(String id) {
284
285 try {
286 HostId hid = HostId.hostId(id);
287 elementOfNote = hostService.getHost(hid);
288
289 } catch (Exception e) {
290 try {
291 DeviceId did = DeviceId.deviceId(id);
292 elementOfNote = deviceService.getDevice(did);
293
294 } catch (Exception e2) {
295 log.debug("Unable to process ID [{}]", id);
296 elementOfNote = null;
297 }
298 }
299
300 switch (currentMode) {
301 case MOUSE:
302 sendMouseData();
303 break;
304
305 default:
306 break;
307 }
308
309 }
310
311 private void clearForMode() {
312 sendHighlights(new Highlights());
313 }
314
315 private void sendHighlights(Highlights highlights) {
316 sendMessage(TopoJson.highlightsMessage(highlights));
317 }
318
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900319 /**
320 * Sends JSON-based message to UI.
321 * @param type type
322 * @param payload payload
323 */
daniel park128c52c2017-09-04 13:15:51 +0900324 public void sendMessagetoUi(String type, ObjectNode payload) {
325 sendMessage(JsonUtils.envelope(type, payload));
326 }
327
328 private int getVni(Host host) {
329 String vni = host.annotations().value(ANNOTATION_SEGMENT_ID);
330
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900331 return vni == null ? 0 : Integer.parseInt(vni);
daniel park128c52c2017-09-04 13:15:51 +0900332 }
333
334 private void sendMouseData() {
335 Highlights highlights = new Highlights();
336
Jian Lib7873422018-08-18 22:34:39 +0900337 if (elementOfNote instanceof Device) {
daniel park128c52c2017-09-04 13:15:51 +0900338 DeviceId deviceId = (DeviceId) elementOfNote.id();
339
340 List<OpenstackLink> edgeLinks = edgeLinks(deviceId);
341
Jian Lib7873422018-08-18 22:34:39 +0900342 edgeLinks.forEach(edgeLink ->
343 highlights.add(edgeLink.highlight(OpenstackLink.RequestType.DEVICE_SELECTED)));
daniel park128c52c2017-09-04 13:15:51 +0900344
345 hostService.getConnectedHosts(deviceId).forEach(host -> {
346 HostHighlight hostHighlight = new HostHighlight(host.id().toString());
347 hostHighlight.setBadge(createBadge(getVni(host)));
348 highlights.add(hostHighlight);
349 });
350
351 sendHighlights(highlights);
352
Jian Lib7873422018-08-18 22:34:39 +0900353 } else if (elementOfNote instanceof Host) {
daniel park128c52c2017-09-04 13:15:51 +0900354
355 HostId hostId = HostId.hostId(elementOfNote.id().toString());
356 if (!hostMadeFromOpenstack(hostId)) {
357 return;
358 }
359
360 List<OpenstackLink> openstackLinks = linksInSameNetwork(hostId);
361
Jian Lib7873422018-08-18 22:34:39 +0900362 openstackLinks.forEach(openstackLink ->
363 highlights.add(openstackLink.highlight(OpenstackLink.RequestType.HOST_SELECTED)));
daniel park128c52c2017-09-04 13:15:51 +0900364
365 hostHighlightsInSameNetwork(hostId).forEach(highlights::add);
366
367 sendHighlights(highlights);
368
369 }
370 }
371
372 private boolean hostMadeFromOpenstack(HostId hostId) {
Jian Lib7873422018-08-18 22:34:39 +0900373 return hostService.getHost(hostId).annotations().value(ANNOTATION_NETWORK_ID) != null;
daniel park128c52c2017-09-04 13:15:51 +0900374 }
375
376 private String networkId(HostId hostId) {
377 return hostService.getHost(hostId).annotations().value(ANNOTATION_NETWORK_ID);
378 }
379
380 private Set<HostHighlight> hostHighlightsInSameNetwork(HostId hostId) {
381
382 Set<HostHighlight> hostHighlights = Sets.newHashSet();
383 Streams.stream(hostService.getHosts())
384 .filter(host -> isHostInSameNetwork(host, networkId(hostId)))
385 .forEach(host -> {
386 HostHighlight hostHighlight = new HostHighlight(host.id().toString());
387 hostHighlight.setBadge(createBadge(getVni(host)));
388 hostHighlights.add(hostHighlight);
389 });
390
391 return hostHighlights;
392 }
393
394 private List<OpenstackLink> edgeLinks(DeviceId deviceId) {
395 OpenstackLinkMap openstackLinkMap = new OpenstackLinkMap();
396
397 hostService.getConnectedHosts(deviceId).forEach(host -> {
398 openstackLinkMap.add(createEdgeLink(host, true));
399 openstackLinkMap.add(createEdgeLink(host, false));
400 });
401
402 List<OpenstackLink> edgeLinks = Lists.newArrayList();
403
Jian Lib7873422018-08-18 22:34:39 +0900404 edgeLinks.addAll(openstackLinkMap.biLinks());
daniel park128c52c2017-09-04 13:15:51 +0900405
406 return edgeLinks;
407 }
408
409 private List<OpenstackLink> linksInSameNetwork(HostId hostId) {
410 OpenstackLinkMap linkMap = new OpenstackLinkMap();
411
412 Streams.stream(hostService.getHosts())
413 .filter(host -> isHostInSameNetwork(host, networkId(hostId)))
414 .forEach(host -> {
415 linkMap.add(createEdgeLink(host, true));
416 linkMap.add(createEdgeLink(host, false));
417
418 Set<Path> paths = pathService.getPaths(hostId,
419 host.id());
420
421 if (!paths.isEmpty()) {
422 paths.forEach(path -> path.links().forEach(linkMap::add));
423 }
424 });
425
426 List<OpenstackLink> openstackLinks = Lists.newArrayList();
427
Jian Lib7873422018-08-18 22:34:39 +0900428 openstackLinks.addAll(linkMap.biLinks());
daniel park128c52c2017-09-04 13:15:51 +0900429
430 return openstackLinks;
431 }
432
433 private boolean isHostInSameNetwork(Host host, String networkId) {
434 return hostService.getHost(host.id()).annotations()
435 .value(ANNOTATION_NETWORK_ID).equals(networkId);
436 }
437
438 private NodeBadge createBadge(int n) {
439 return NodeBadge.number(Status.INFO, n, "Openstack Node");
440 }
Daniel Park577b69c2018-07-16 17:29:34 +0900441
boyoung27b444122018-09-01 17:28:13 +0900442 private void processFlowStatsRequest(String srcIp, String dstIp, Boolean install) {
443 boolean statsSuccess = true;
444 ObjectMapper mapper = new ObjectMapper();
445 ObjectNode statsResult = mapper.createObjectNode();
446
447 statsFlowRuleService.setStatFlowL2Rule(srcIp, dstIp, install);
448 statsResult.put(STATS_SUCCESS, statsSuccess);
449 sendMessagetoUi(FLOW_STATS_ADD_RESULT, statsResult);
450 }
451
Daniel Park4e037f52018-09-20 18:04:18 +0900452 private void processFlowTraceRequest(String srcIp, String dstIp, String srcDeviceId, String dstDeviceId,
453 boolean uplink) {
Daniel Park577b69c2018-07-16 17:29:34 +0900454 boolean traceSuccess = true;
455
456 ObjectMapper mapper = new ObjectMapper();
457
458 ObjectNode traceResult = mapper.createObjectNode();
459
460 ArrayNode traceResultArray = traceResult.putArray(TRACE_RESULT);
461
462 OpenstackNode srcOpenstackNode = osNodeService.node(DeviceId.deviceId(srcDeviceId));
463 if (srcOpenstackNode == null) {
Daniel Park4e037f52018-09-20 18:04:18 +0900464 log.error("There's no openstack node information for device {}", srcDeviceId);
Daniel Park577b69c2018-07-16 17:29:34 +0900465 return;
466 }
467
468 if (srcOpenstackNode.sshAuthInfo() == null) {
469 log.error("Openstack node {} has no SSH authentication information..",
470 srcOpenstackNode.hostname());
471 return;
472 }
473
Daniel Park4e037f52018-09-20 18:04:18 +0900474 String traceResultString = sendTraceRequestToNode(srcIp, dstIp, srcOpenstackNode, uplink);
475
476 if (traceResultString == null) {
Daniel Park577b69c2018-07-16 17:29:34 +0900477 return;
478 }
479
Daniel Park4e037f52018-09-20 18:04:18 +0900480 log.debug("traceResultString raw data: {}", traceResultString);
Daniel Park577b69c2018-07-16 17:29:34 +0900481
Daniel Park4e037f52018-09-20 18:04:18 +0900482 ObjectNode traceResultJson = null;
Daniel Park577b69c2018-07-16 17:29:34 +0900483
484 Device srcDevice = deviceService.getDevice(srcOpenstackNode.intgBridge());
Daniel Park4e037f52018-09-20 18:04:18 +0900485 if (srcDevice.swVersion().startsWith(OVS_VERSION_2_8) ||
486 srcDevice.swVersion().startsWith(OVS_VERSION_2_7)) {
487 traceResultJson = Ovs28FlowTraceResultParser.flowTraceResultInJson(
488 traceResultString.trim(), srcOpenstackNode.hostname());
Daniel Park577b69c2018-07-16 17:29:34 +0900489 } else {
490 log.error("Currently OVS version {} is not supported",
491 deviceService.getDevice(srcOpenstackNode.intgBridge()));
492 }
493
Daniel Park4e037f52018-09-20 18:04:18 +0900494 if (traceResultJson == null) {
Daniel Park577b69c2018-07-16 17:29:34 +0900495 return;
496 }
497
Daniel Park4e037f52018-09-20 18:04:18 +0900498 traceResultArray.add(traceResultJson);
Daniel Park577b69c2018-07-16 17:29:34 +0900499
Daniel Park4e037f52018-09-20 18:04:18 +0900500 log.debug("traceResultForward Json: {}", traceResultJson);
Daniel Park577b69c2018-07-16 17:29:34 +0900501
Daniel Park4e037f52018-09-20 18:04:18 +0900502 if (!traceResultJson.get(IS_SUCCESS).asBoolean()) {
Daniel Park577b69c2018-07-16 17:29:34 +0900503 traceSuccess = false;
504 }
505
Daniel Park577b69c2018-07-16 17:29:34 +0900506 traceResult.put(TRACE_SUCCESS, traceSuccess);
Daniel Park4e037f52018-09-20 18:04:18 +0900507
508 traceResult.put(SRC_IP, srcIp);
509 traceResult.put(DST_IP, dstIp);
510 traceResult.put(SRC_DEVICE_ID, srcDeviceId);
511 traceResult.put(DST_DEVICE_ID, dstDeviceId);
512 traceResult.put(UPLINK, uplink);
513
Daniel Park577b69c2018-07-16 17:29:34 +0900514 log.debug("traceResult Json: {}", traceResult);
515
516 sendMessagetoUi(FLOW_TRACE_RESULT, traceResult);
517
518 }
519
Daniel Park4e037f52018-09-20 18:04:18 +0900520 private String sendTraceRequestToNode(String srcIp, String dstIp, OpenstackNode openstackNode, boolean uplink) {
521
522 Optional<InstancePort> instancePort = instancePortService.instancePorts().stream()
523 .filter(port -> port.ipAddress().getIp4Address().toString().equals(srcIp)
524 && port.deviceId().equals(openstackNode.intgBridge()))
525 .findAny();
526
527 if (!instancePort.isPresent()) {
528 return null;
529 }
530
531 String requestString = traceRequestString(srcIp, dstIp,
532 instancePort.get(), osNetService, uplink);
533
534 return sendTraceRequestToNode(requestString, openstackNode);
535 }
536
537 private String traceRequestString(String srcIp,
538 String dstIp,
539 InstancePort srcInstancePort,
540 OpenstackNetworkService osNetService,
541 boolean uplink) {
542
543 StringBuilder requestStringBuilder = new StringBuilder(DEFAULT_REQUEST_STRING);
544
545 if (uplink) {
546
547 requestStringBuilder.append(COMMA)
548 .append(IN_PORT)
549 .append(srcInstancePort.portNumber().toString())
550 .append(COMMA)
551 .append(NW_SRC)
552 .append(srcIp)
553 .append(COMMA);
554
555 if (osNetService.networkType(srcInstancePort.networkId()).equals(VXLAN) ||
556 osNetService.networkType(srcInstancePort.networkId()).equals(VLAN)) {
557 if (srcIp.equals(dstIp)) {
558 dstIp = osNetService.gatewayIp(srcInstancePort.portId());
559 requestStringBuilder.append(DL_DST)
560 .append(DEFAULT_GATEWAY_MAC_STR).append(COMMA);
561 } else if (!osNetService.ipPrefix(srcInstancePort.portId()).contains(IpAddress.valueOf(dstIp))) {
562 requestStringBuilder.append(DL_DST)
563 .append(DEFAULT_GATEWAY_MAC_STR)
564 .append(COMMA);
565 }
566 } else {
567 if (srcIp.equals(dstIp)) {
568 dstIp = osNetService.gatewayIp(srcInstancePort.portId());
569 }
570 }
571
572 requestStringBuilder.append(NW_DST)
573 .append(dstIp)
574 .append("\n");
575 } else {
576 requestStringBuilder.append(COMMA)
577 .append(NW_SRC)
578 .append(dstIp)
579 .append(COMMA);
580
581 if (osNetService.networkType(srcInstancePort.networkId()).equals(VXLAN) ||
582 osNetService.networkType(srcInstancePort.networkId()).equals(VLAN)) {
583 requestStringBuilder.append(TUN_ID)
584 .append(osNetService.segmentId(srcInstancePort.networkId()))
585 .append(COMMA);
586 }
587 requestStringBuilder.append(NW_DST)
588 .append(srcIp)
589 .append("\n");
590
591 }
592
593 return requestStringBuilder.toString();
594 }
595
596 private String sendTraceRequestToNode(String requestString,
597 OpenstackNode node) {
Daniel Park577b69c2018-07-16 17:29:34 +0900598 String traceResult = null;
Daniel Park4e037f52018-09-20 18:04:18 +0900599 OpenstackSshAuth sshAuth = node.sshAuthInfo();
Daniel Park577b69c2018-07-16 17:29:34 +0900600
601 try (SshClient client = SshClient.setUpDefaultClient()) {
602 client.start();
603
604 try (ClientSession session = client
Daniel Park4e037f52018-09-20 18:04:18 +0900605 .connect(sshAuth.id(), node.managementIp().getIp4Address().toString(), SSH_PORT)
Daniel Park577b69c2018-07-16 17:29:34 +0900606 .verify(TIMEOUT_MS, TimeUnit.SECONDS).getSession()) {
607 session.addPasswordIdentity(sshAuth.password());
608 session.auth().verify(TIMEOUT_MS, TimeUnit.SECONDS);
609
610
611 try (ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) {
612
Daniel Park577b69c2018-07-16 17:29:34 +0900613 log.debug("requestString: {}", requestString);
614 final InputStream inputStream =
615 new ByteArrayInputStream(requestString.getBytes());
616
617 OutputStream outputStream = new ByteArrayOutputStream();
618 OutputStream errStream = new ByteArrayOutputStream();
619
620 channel.setIn(new NoCloseInputStream(inputStream));
621 channel.setErr(errStream);
622 channel.setOut(outputStream);
623
624 Collection<ClientChannelEvent> eventList = Lists.newArrayList();
625 eventList.add(ClientChannelEvent.OPENED);
626
627 OpenFuture channelFuture = channel.open();
628
629 if (channelFuture.await(TIMEOUT_MS, TimeUnit.SECONDS)) {
630
631 long timeoutExpiredMs = System.currentTimeMillis() + TIMEOUT_MS;
632
633 while (!channelFuture.isOpened()) {
634 if ((timeoutExpiredMs - System.currentTimeMillis()) <= 0) {
635 log.error("Failed to open channel");
636 return null;
637 }
638 }
639 TimeUnit.SECONDS.sleep(WAIT_OUTPUT_STREAM_SECOND);
640
641 traceResult = ((ByteArrayOutputStream) outputStream).toString(Charsets.UTF_8.name());
642
643 channel.close();
644 }
645 } finally {
646 session.close();
647 }
648 } finally {
649 client.stop();
650 }
651
652 } catch (Exception e) {
653 log.error("Exception occurred because of {}", e.toString());
654 }
655
Daniel Parkbbdf4ba2018-07-23 16:23:42 +0900656 return traceResult;
Daniel Park577b69c2018-07-16 17:29:34 +0900657 }
daniel park128c52c2017-09-04 13:15:51 +0900658}