From 4e037f5c2fb01b7abc8d64e93a4b07dfa0ff0c86 Mon Sep 17 00:00:00 2001 From: Daniel Park Date: Thu, 20 Sep 2018 18:04:18 +0900 Subject: [PATCH] Supports downlink trace functionality in OpenstackNetworkingUI Change-Id: Ide25681e83d34b22393483b3b06e8834693a18ec (cherry picked from commit 5aef9826f6232d2605bbe11a97b9487c56f575a4) --- apps/openstacknetworking/api/BUCK | 1 + apps/openstacknetworking/api/BUILD | 1 + .../util/OpenstackNetworkingUtil.java | 2 +- apps/openstacknetworkingui/BUCK | 1 + apps/openstacknetworkingui/BUILD | 1 + .../OpenstackNetworkingUiMessageHandler.java | 177 ++++++++++++------ .../app/view/sonaTopov/sonaTopovOverlay.js | 4 +- .../app/view/sonaTopov/sonaTopovService.js | 40 +++- 8 files changed, 156 insertions(+), 71 deletions(-) diff --git a/apps/openstacknetworking/api/BUCK b/apps/openstacknetworking/api/BUCK index cbc9b22728..61b333d6cc 100644 --- a/apps/openstacknetworking/api/BUCK +++ b/apps/openstacknetworking/api/BUCK @@ -3,6 +3,7 @@ include_defs('//apps/openstacknode/openstack4j.bucklet') COMPILE_DEPS = [ '//lib:CORE_DEPS', '//lib:openstack4j-core', + "//apps/openstacknode/api:onos-apps-openstacknode-api", ] osgi_jar_with_tests ( diff --git a/apps/openstacknetworking/api/BUILD b/apps/openstacknetworking/api/BUILD index 5348b6042a..9ead93282f 100644 --- a/apps/openstacknetworking/api/BUILD +++ b/apps/openstacknetworking/api/BUILD @@ -7,6 +7,7 @@ load( COMPILE_DEPS = CORE_DEPS + [ "@openstack4j_core//jar", + "//apps/openstacknode/api:onos-apps-openstacknode-api", ] osgi_jar_with_tests( diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java index d06065c138..65a9e9f87f 100644 --- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java +++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java @@ -700,7 +700,7 @@ public final class OpenstackNetworkingUtil { * @param dstIp dst ip address * @param srcInstancePort src instance port * @param osNetService openstack networking service - * @param uplink true if this request if uplink + * @param uplink true if this request is for uplink * @return flow trace request string */ public static String traceRequestString(String srcIp, diff --git a/apps/openstacknetworkingui/BUCK b/apps/openstacknetworkingui/BUCK index 12f126440b..2f2fe68327 100644 --- a/apps/openstacknetworkingui/BUCK +++ b/apps/openstacknetworkingui/BUCK @@ -11,6 +11,7 @@ COMPILE_DEPS = [ '//apps/openstacknode/api:onos-apps-openstacknode-api', '//apps/openstacktelemetry/api:onos-apps-openstacktelemetry-api', '//apps/openstacknetworking/api:onos-apps-openstacknetworking-api', + '//apps/openstacknetworking/app:onos-apps-openstacknetworking-app', ] EXCLUDED_BUNDLES = [ diff --git a/apps/openstacknetworkingui/BUILD b/apps/openstacknetworkingui/BUILD index 5058dd125c..ed4f724dd3 100644 --- a/apps/openstacknetworkingui/BUILD +++ b/apps/openstacknetworkingui/BUILD @@ -8,6 +8,7 @@ COMPILE_DEPS = CORE_DEPS + JACKSON + CLI + REST + [ "//apps/openstacknode/api:onos-apps-openstacknode-api", "//apps/openstacktelemetry/api:onos-apps-openstacktelemetry-api", "//apps/openstacknetworking/api:onos-apps-openstacknetworking-api", + "//apps/openstacknetworking/app:onos-apps-openstacknetworking-app", "@sshd_core//jar", ] diff --git a/apps/openstacknetworkingui/src/main/java/org/onosproject/openstacknetworkingui/OpenstackNetworkingUiMessageHandler.java b/apps/openstacknetworkingui/src/main/java/org/onosproject/openstacknetworkingui/OpenstackNetworkingUiMessageHandler.java index c49944df3e..32964af592 100644 --- a/apps/openstacknetworkingui/src/main/java/org/onosproject/openstacknetworkingui/OpenstackNetworkingUiMessageHandler.java +++ b/apps/openstacknetworkingui/src/main/java/org/onosproject/openstacknetworkingui/OpenstackNetworkingUiMessageHandler.java @@ -104,17 +104,20 @@ public class OpenstackNetworkingUiMessageHandler extends UiMessageHandler { private static final String FLOW_TRACE_RESULT = "flowTraceResult"; private static final String SRC_DEVICE_ID = "srcDeviceId"; private static final String DST_DEVICE_ID = "dstDeviceId"; + private static final String UPLINK = "uplink"; private static final String OVS_VERSION_2_8 = "2.8"; + private static final String OVS_VERSION_2_7 = "2.7"; private static final String OVS_VERSION_2_6 = "2.6"; - private static final String FLAT = "FLAT"; + private static final String VXLAN = "VXLAN"; private static final String VLAN = "VLAN"; private static final String DL_DST = "dl_dst="; private static final String NW_DST = "nw_dst="; - private static final String DEFAULT_REQUEST_STRING = "sudo ovs-appctl ofproto/trace br-int ip,in_port="; + private static final String DEFAULT_REQUEST_STRING = "sudo ovs-appctl ofproto/trace br-int ip"; + private static final String IN_PORT = "in_port="; private static final String NW_SRC = "nw_src="; private static final String COMMA = ","; - + private static final String TUN_ID = "tun_id="; private static final long TIMEOUT_MS = 5000; private static final long WAIT_OUTPUT_STREAM_SECOND = 2; @@ -230,12 +233,15 @@ public class OpenstackNetworkingUiMessageHandler extends UiMessageHandler { String dstIp = string(payload, DST_IP); String srcDeviceId = string(payload, SRC_DEVICE_ID); String dstDeviceId = string(payload, DST_DEVICE_ID); - log.info("Flow trace request called with src IP: {}, dst IP: {}, src device ID: {}, dst device Id: {}", + boolean uplink = bool(payload, UPLINK); + log.info("Flow trace request called with" + + "src IP: {}, dst IP: {}, src device ID: {}, dst device Id: {}, uplink: ", srcIp, dstIp, srcDeviceId, - dstDeviceId); - eventExecutor.execute(() -> processFlowTraceRequest(srcIp, dstIp, srcDeviceId)); + dstDeviceId, + uplink); + eventExecutor.execute(() -> processFlowTraceRequest(srcIp, dstIp, srcDeviceId, dstDeviceId, uplink)); } } @@ -443,7 +449,8 @@ public class OpenstackNetworkingUiMessageHandler extends UiMessageHandler { sendMessagetoUi(FLOW_STATS_ADD_RESULT, statsResult); } - private void processFlowTraceRequest(String srcIp, String dstIp, String srcDeviceId) { + private void processFlowTraceRequest(String srcIp, String dstIp, String srcDeviceId, String dstDeviceId, + boolean uplink) { boolean traceSuccess = true; ObjectMapper mapper = new ObjectMapper(); @@ -454,6 +461,7 @@ public class OpenstackNetworkingUiMessageHandler extends UiMessageHandler { OpenstackNode srcOpenstackNode = osNodeService.node(DeviceId.deviceId(srcDeviceId)); if (srcOpenstackNode == null) { + log.error("There's no openstack node information for device {}", srcDeviceId); return; } @@ -463,52 +471,138 @@ public class OpenstackNetworkingUiMessageHandler extends UiMessageHandler { return; } - String traceResultForward = sendTraceRequestToNode(srcIp, dstIp, srcOpenstackNode); - if (traceResultForward == null) { + String traceResultString = sendTraceRequestToNode(srcIp, dstIp, srcOpenstackNode, uplink); + + if (traceResultString == null) { return; } - log.debug("traceResultForward raw data: {}", traceResultForward); + log.debug("traceResultString raw data: {}", traceResultString); - ObjectNode traceResultForwardJson = null; + ObjectNode traceResultJson = null; Device srcDevice = deviceService.getDevice(srcOpenstackNode.intgBridge()); - if (srcDevice.swVersion().startsWith(OVS_VERSION_2_8)) { - traceResultForwardJson = Ovs28FlowTraceResultParser.flowTraceResultInJson( - traceResultForward.trim(), srcOpenstackNode.hostname()); + if (srcDevice.swVersion().startsWith(OVS_VERSION_2_8) || + srcDevice.swVersion().startsWith(OVS_VERSION_2_7)) { + traceResultJson = Ovs28FlowTraceResultParser.flowTraceResultInJson( + traceResultString.trim(), srcOpenstackNode.hostname()); } else { log.error("Currently OVS version {} is not supported", deviceService.getDevice(srcOpenstackNode.intgBridge())); } - if (traceResultForwardJson == null) { + if (traceResultJson == null) { return; } - traceResultArray.add(traceResultForwardJson); + traceResultArray.add(traceResultJson); - log.debug("traceResultForward Json: {}", traceResultForwardJson); + log.debug("traceResultForward Json: {}", traceResultJson); - if (!traceResultForwardJson.get(IS_SUCCESS).asBoolean()) { + if (!traceResultJson.get(IS_SUCCESS).asBoolean()) { traceSuccess = false; } traceResult.put(TRACE_SUCCESS, traceSuccess); + + traceResult.put(SRC_IP, srcIp); + traceResult.put(DST_IP, dstIp); + traceResult.put(SRC_DEVICE_ID, srcDeviceId); + traceResult.put(DST_DEVICE_ID, dstDeviceId); + traceResult.put(UPLINK, uplink); + log.debug("traceResult Json: {}", traceResult); sendMessagetoUi(FLOW_TRACE_RESULT, traceResult); } - private String sendTraceRequestToNode(String srcIp, String dstIp, OpenstackNode openstackNode) { + private String sendTraceRequestToNode(String srcIp, String dstIp, OpenstackNode openstackNode, boolean uplink) { + + Optional instancePort = instancePortService.instancePorts().stream() + .filter(port -> port.ipAddress().getIp4Address().toString().equals(srcIp) + && port.deviceId().equals(openstackNode.intgBridge())) + .findAny(); + + if (!instancePort.isPresent()) { + return null; + } + + String requestString = traceRequestString(srcIp, dstIp, + instancePort.get(), osNetService, uplink); + + return sendTraceRequestToNode(requestString, openstackNode); + } + + private String traceRequestString(String srcIp, + String dstIp, + InstancePort srcInstancePort, + OpenstackNetworkService osNetService, + boolean uplink) { + + StringBuilder requestStringBuilder = new StringBuilder(DEFAULT_REQUEST_STRING); + + if (uplink) { + + requestStringBuilder.append(COMMA) + .append(IN_PORT) + .append(srcInstancePort.portNumber().toString()) + .append(COMMA) + .append(NW_SRC) + .append(srcIp) + .append(COMMA); + + if (osNetService.networkType(srcInstancePort.networkId()).equals(VXLAN) || + osNetService.networkType(srcInstancePort.networkId()).equals(VLAN)) { + if (srcIp.equals(dstIp)) { + dstIp = osNetService.gatewayIp(srcInstancePort.portId()); + requestStringBuilder.append(DL_DST) + .append(DEFAULT_GATEWAY_MAC_STR).append(COMMA); + } else if (!osNetService.ipPrefix(srcInstancePort.portId()).contains(IpAddress.valueOf(dstIp))) { + requestStringBuilder.append(DL_DST) + .append(DEFAULT_GATEWAY_MAC_STR) + .append(COMMA); + } + } else { + if (srcIp.equals(dstIp)) { + dstIp = osNetService.gatewayIp(srcInstancePort.portId()); + } + } + + requestStringBuilder.append(NW_DST) + .append(dstIp) + .append("\n"); + } else { + requestStringBuilder.append(COMMA) + .append(NW_SRC) + .append(dstIp) + .append(COMMA); + + if (osNetService.networkType(srcInstancePort.networkId()).equals(VXLAN) || + osNetService.networkType(srcInstancePort.networkId()).equals(VLAN)) { + requestStringBuilder.append(TUN_ID) + .append(osNetService.segmentId(srcInstancePort.networkId())) + .append(COMMA); + } + requestStringBuilder.append(NW_DST) + .append(srcIp) + .append("\n"); + + } + + return requestStringBuilder.toString(); + } + + private String sendTraceRequestToNode(String requestString, + OpenstackNode node) { String traceResult = null; - OpenstackSshAuth sshAuth = openstackNode.sshAuthInfo(); + OpenstackSshAuth sshAuth = node.sshAuthInfo(); try (SshClient client = SshClient.setUpDefaultClient()) { client.start(); try (ClientSession session = client - .connect(sshAuth.id(), openstackNode.managementIp().getIp4Address().toString(), SSH_PORT) + .connect(sshAuth.id(), node.managementIp().getIp4Address().toString(), SSH_PORT) .verify(TIMEOUT_MS, TimeUnit.SECONDS).getSession()) { session.addPasswordIdentity(sshAuth.password()); session.auth().verify(TIMEOUT_MS, TimeUnit.SECONDS); @@ -516,11 +610,6 @@ public class OpenstackNetworkingUiMessageHandler extends UiMessageHandler { try (ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) { - String requestString = traceRequestString(srcIp, dstIp, openstackNode); - if (requestString == null) { - return null; - } - log.debug("requestString: {}", requestString); final InputStream inputStream = new ByteArrayInputStream(requestString.getBytes()); @@ -566,40 +655,4 @@ public class OpenstackNetworkingUiMessageHandler extends UiMessageHandler { return traceResult; } - - private String traceRequestString(String srcIp, String dstIp, OpenstackNode openstackNode) { - - Optional instancePort = instancePortService.instancePorts().stream() - .filter(port -> port.ipAddress().getIp4Address().toString().equals(srcIp) - && port.deviceId().equals(openstackNode.intgBridge())) - .findAny(); - - if (!instancePort.isPresent()) { - return null; - } - - String requestString = DEFAULT_REQUEST_STRING - + instancePort.get().portNumber().toString() - + COMMA - + NW_SRC - + srcIp - + COMMA; - - if (osNetService.networkType(instancePort.get().networkId()).equals(VXLAN)) { - if (srcIp.equals(dstIp)) { - dstIp = osNetService.gatewayIp(instancePort.get().portId()); - requestString = requestString + DL_DST + DEFAULT_GATEWAY_MAC_STR + COMMA; - } else if (!osNetService.ipPrefix(instancePort.get().portId()).contains(IpAddress.valueOf(dstIp))) { - requestString = requestString + DL_DST + DEFAULT_GATEWAY_MAC_STR + COMMA; - } - } else if (osNetService.networkType(instancePort.get().networkId()).equals(FLAT)) { - if (srcIp.equals(dstIp)) { - dstIp = osNetService.gatewayIp(instancePort.get().portId()); - } - } - - requestString = requestString + NW_DST + dstIp + "\n"; - - return requestString; - } } diff --git a/apps/openstacknetworkingui/src/main/resources/app/view/sonaTopov/sonaTopovOverlay.js b/apps/openstacknetworkingui/src/main/resources/app/view/sonaTopov/sonaTopovOverlay.js index e588cb2509..b2d799964b 100644 --- a/apps/openstacknetworkingui/src/main/resources/app/view/sonaTopov/sonaTopovOverlay.js +++ b/apps/openstacknetworkingui/src/main/resources/app/view/sonaTopov/sonaTopovOverlay.js @@ -28,7 +28,7 @@ var flowStatsDstIp = null; var traceInfoDialogId = 'traceInfoDialogId', - traceInfoDialogOpt = { + traceInfoDialogOpt = { width: 350, edge: 'left', margin: 20, @@ -278,7 +278,7 @@ } function flowTraceResultBtn() { - sts.sendFlowTraceRequest(traceSrc, traceDst, srcDeviceId, dstDeviceId); + sts.sendFlowTraceRequest(traceSrc, traceDst, srcDeviceId, dstDeviceId, true); ds.closeDialog(); traceSrc = null; traceDst = null; diff --git a/apps/openstacknetworkingui/src/main/resources/app/view/sonaTopov/sonaTopovService.js b/apps/openstacknetworkingui/src/main/resources/app/view/sonaTopov/sonaTopovService.js index 0212ea239e..21b495b875 100644 --- a/apps/openstacknetworkingui/src/main/resources/app/view/sonaTopov/sonaTopovService.js +++ b/apps/openstacknetworkingui/src/main/resources/app/view/sonaTopov/sonaTopovService.js @@ -28,6 +28,12 @@ // injected refs var $log, fs, flash, wss, ds; + var traceSrc = null; + var traceDst = null; + var srcDeviceId = null; + var dstDeviceId = null; + var uplink = null; + // constants var displayStart = 'openstackNetworkingUiStart', displayUpdate = 'openstackNetworkingUiUpdate', @@ -76,12 +82,13 @@ flash.flash('sendFlowStatsRemoveRequest called'); } - function sendFlowTraceRequest(src, dst, srcDeviceId, dstDeviceId) { + function sendFlowTraceRequest(src, dst, srcDeviceId, dstDeviceId, uplink) { wss.sendEvent(flowTraceRequest, { srcIp: src, dstIp: dst, srcDeviceId: srcDeviceId, dstDeviceId: dstDeviceId, + uplink: uplink, }); flash.flash('sendFlowTraceRequest called'); } @@ -175,11 +182,32 @@ hideMargin: -20 } var traceSuccess = data.traceSuccess == true ? "SUCCESS" : "FALSE"; - ds.openDialog(flowTraceResultDialogId, flowTraceResultDialogOpt) - .setTitle('Flow Trace Result: ' + traceSuccess) - .addContent(createTraceResultInfoDiv(data)) - .addOk(dOk, 'Close') - .bindKeys(); + traceSrc = data.srcIp; + traceDst = data.dstIp; + srcDeviceId = data.srcDeviceId; + dstDeviceId = data.dstDeviceId; + uplink = data.uplink; + + if (data.uplink == true) { + ds.openDialog(flowTraceResultDialogId, flowTraceResultDialogOpt) + .setTitle('Flow Trace Result: ' + traceSuccess) + .addContent(createTraceResultInfoDiv(data)) + .addOk(downlinkTraceRequestBtn, 'Downlink Trace') + .bindKeys(); + } else { + ds.openDialog(flowTraceResultDialogId, flowTraceResultDialogOpt) + .setTitle('Flow Trace Result: ' + traceSuccess) + .addContent(createTraceResultInfoDiv(data)) + .addOk(dOk, 'Close') + .bindKeys(); + } + + } + + function downlinkTraceRequestBtn() { + sendFlowTraceRequest(traceSrc, traceDst, srcDeviceId, dstDeviceId, false); + ds.closeDialog(); + flash.flash('Send Downlink Flow Trace Request') } function createTraceResultInfoDiv(data) {