/* * Copyright 2016-present Open Networking Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onosproject.sfcweb; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.collect.ImmutableSet; import jersey.repackaged.com.google.common.collect.Lists; import org.onlab.osgi.DefaultServiceDirectory; import org.onlab.osgi.ServiceDirectory; import org.onlab.packet.MacAddress; import org.onosproject.net.DeviceId; import org.onosproject.net.Element; import org.onosproject.net.Host; import org.onosproject.net.HostId; import org.onosproject.net.Link; import org.onosproject.net.host.HostService; import org.onosproject.net.link.LinkService; import org.onosproject.ui.RequestHandler; import org.onosproject.ui.UiConnection; import org.onosproject.ui.UiMessageHandler; import org.onosproject.ui.topo.DeviceHighlight; import org.onosproject.ui.topo.Highlights; import org.onosproject.ui.topo.HostHighlight; import org.onosproject.ui.topo.NodeBadge; import org.onosproject.ui.topo.TopoJson; import org.onosproject.vtnrsc.FiveTuple; import org.onosproject.vtnrsc.LoadBalanceId; import org.onosproject.vtnrsc.PortChain; import org.onosproject.vtnrsc.PortChainId; import org.onosproject.vtnrsc.PortPair; import org.onosproject.vtnrsc.PortPairId; import org.onosproject.vtnrsc.VirtualPort; import org.onosproject.vtnrsc.VirtualPortId; import org.onosproject.vtnrsc.portchain.PortChainService; import org.onosproject.vtnrsc.portpair.PortPairService; import org.onosproject.vtnrsc.portpairgroup.PortPairGroupService; import org.onosproject.vtnrsc.service.VtnRscService; import org.onosproject.vtnrsc.virtualport.VirtualPortService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.List; import java.util.ListIterator; import java.util.Set; import java.util.TimerTask; import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; /** * SFC web gui topology-overlay message handler. */ public class SfcwebUiTopovMessageHandler extends UiMessageHandler { private static final String SAMPLE_TOPOV_DISPLAY_START = "sfcwebTopovDisplayStart"; private static final String SAMPLE_TOPOV_DISPLAY_SFC = "showSfcInfo"; private static final String SAMPLE_TOPOV_DISPLAY_STOP = "sfcTopovClear"; private static final String CONFIG_SFP_MSG = "configSfpMessage"; private static final String SAMPLE_TOPOV_SHOW_SFC_PATH = "showSfcPath"; private static final String ID = "id"; private static final String MODE = "mode"; private static final String CLASSIFIER = "CLS"; private static final String FORWARDER = "SFF"; private static final Link[] EMPTY_LINK_SET = new Link[0]; private enum Mode { IDLE, MOUSE, LINK } private final Logger log = LoggerFactory.getLogger(getClass()); private HostService hostService; private LinkService linkService; private TimerTask demoTask = null; private Mode currentMode = Mode.IDLE; private Element elementOfNote; private Link[] linkSet = EMPTY_LINK_SET; protected PortPairService portPairService; protected VtnRscService vtnRscService; protected VirtualPortService virtualPortService; protected PortChainService portChainService; protected PortPairGroupService portPairGroupService; @Override public void init(UiConnection connection, ServiceDirectory directory) { super.init(connection, directory); hostService = directory.get(HostService.class); linkService = directory.get(LinkService.class); portChainService = directory.get(PortChainService.class); portPairService = directory.get(PortPairService.class); portPairGroupService = directory.get(PortPairGroupService.class); } @Override protected Collection<RequestHandler> createRequestHandlers() { return ImmutableSet.of( new DisplayStartHandler(), new DisplayStopHandler(), new ConfigSfpMsg() ); } /** * Handler classes. */ private final class DisplayStartHandler extends RequestHandler { public DisplayStartHandler() { super(SAMPLE_TOPOV_DISPLAY_START); } @Override public void process(ObjectNode payload) { String mode = string(payload, MODE); PortChainService pcs = get(PortChainService.class); Iterable<PortChain> portChains = pcs.getPortChains(); ObjectNode result = objectNode(); ArrayNode arrayNode = arrayNode(); for (final PortChain portChain : portChains) { arrayNode.add(portChain.portChainId().value().toString()); } result.putArray("a").addAll(arrayNode); sendMessage(SAMPLE_TOPOV_DISPLAY_SFC, result); } } private final class DisplayStopHandler extends RequestHandler { public DisplayStopHandler() { super(SAMPLE_TOPOV_DISPLAY_STOP); } @Override public void process(ObjectNode payload) { log.debug("Stop Display"); clearState(); clearForMode(); cancelTask(); } } private final class ConfigSfpMsg extends RequestHandler { public ConfigSfpMsg() { super(CONFIG_SFP_MSG); } @Override public void process(ObjectNode payload) { String id = string(payload, ID); ServiceDirectory serviceDirectory = new DefaultServiceDirectory(); vtnRscService = serviceDirectory.get(VtnRscService.class); virtualPortService = serviceDirectory.get(VirtualPortService.class); List<String> sfcPathList = Lists.newArrayList(); Highlights highlights = new Highlights(); SfcLinkMap linkMap = new SfcLinkMap(); PortChainId portChainId = PortChainId.of(id); boolean portChainIdExist = portChainService.exists(portChainId); if (!portChainIdExist) { log.info("portchain id doesn't exist"); return; } PortChain portChain = portChainService.getPortChain(portChainId); Set<FiveTuple> fiveTupleSet = portChain.getLoadBalanceIdMapKeys(); for (FiveTuple fiveTuple : fiveTupleSet) { List<PortPairId> path = portChain.getLoadBalancePath(fiveTuple); LoadBalanceId lbId = portChain.getLoadBalanceId(fiveTuple); ListIterator<PortPairId> pathIterator = path.listIterator(); // Add source Host srcHost = hostService.getHost(HostId.hostId(fiveTuple.macSrc())); HostHighlight hSrc = new HostHighlight(srcHost.id().toString()); hSrc.setBadge(NodeBadge.text("SRC")); String sfcPath = "SRC -> "; highlights.add(hSrc); DeviceId previousDeviceId = null; while (pathIterator.hasNext()) { PortPairId portPairId = pathIterator.next(); PortPair portPair = portPairService.getPortPair(portPairId); DeviceId deviceId = vtnRscService.getSfToSffMaping(VirtualPortId.portId(portPair.egress())); VirtualPort vPort = virtualPortService.getPort(VirtualPortId.portId(portPair.egress())); MacAddress dstMacAddress = vPort.macAddress(); Host host = hostService.getHost(HostId.hostId(dstMacAddress)); addEdgeLinks(linkMap, host); log.info("before check"); if (previousDeviceId != null) { log.info("pdid not null"); if (!deviceId.equals(previousDeviceId)) { // Highlight the link between devices. Link link = getLinkBetweenDevices(deviceId, previousDeviceId); if (link != null) { linkMap.add(link); } } } DeviceHighlight dh = new DeviceHighlight(deviceId.toString()); if (portChain.getSfcClassifiers(lbId).contains(deviceId)) { dh.setBadge(NodeBadge.text(CLASSIFIER)); } else { dh.setBadge(NodeBadge.text(FORWARDER)); } highlights.add(dh); HostHighlight hhDst = new HostHighlight(host.id().toString()); hhDst.setBadge(NodeBadge.text(portPair.name())); sfcPath = sfcPath + portPair.name() + "(" + vPort.fixedIps().iterator().next().ip() + ") -> "; if (!portPair.ingress().equals(portPair.egress())) { MacAddress srcMacAddress = virtualPortService.getPort(VirtualPortId .portId(portPair.ingress())) .macAddress(); Host hostSrc = hostService.getHost(HostId.hostId(srcMacAddress)); HostHighlight hhSrc = new HostHighlight(hostSrc.id().toString()); hhSrc.setBadge(NodeBadge.text(portPair.name())); highlights.add(hhSrc); } highlights.add(hhDst); previousDeviceId = deviceId; } // Add destination Host dstHost = hostService.getHost(HostId.hostId(fiveTuple.macDst())); HostHighlight hDst = new HostHighlight(dstHost.id().toString()); hDst.setBadge(NodeBadge.text("DST")); sfcPath = sfcPath + "DST"; highlights.add(hDst); sfcPathList.add(sfcPath); } for (SfcLink sfcLink : linkMap.biLinks()) { highlights.add(sfcLink.highlight(null)); } sendHighlights(highlights); ObjectNode result = objectNode(); ArrayNode arrayNode = arrayNode(); for (String path : sfcPathList) { arrayNode.add(path); } result.putArray("sfcPathList").addAll(arrayNode); sendMessage(SAMPLE_TOPOV_SHOW_SFC_PATH, result); } } private Link getLinkBetweenDevices(DeviceId deviceId, DeviceId previousDeviceId) { Set<Link> deviceLinks = linkService.getDeviceEgressLinks(deviceId); Set<Link> previousDeviceLinks = linkService.getDeviceIngressLinks(previousDeviceId); for (Link link : deviceLinks) { previousDeviceLinks.contains(link); return link; } return null; } private void addEdgeLinks(SfcLinkMap linkMap, Host host1) { linkMap.add(createEdgeLink(host1, true)); linkMap.add(createEdgeLink(host1, false)); } private synchronized void cancelTask() { if (demoTask != null) { demoTask.cancel(); demoTask = null; } } private void clearState() { currentMode = Mode.IDLE; elementOfNote = null; linkSet = EMPTY_LINK_SET; } private void clearForMode() { sendHighlights(new Highlights()); } private void sendHighlights(Highlights highlights) { sendMessage(TopoJson.highlightsMessage(highlights)); } }