--- /dev/null
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.topologymanager.internal;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.felix.dm.Component;
+import org.eclipse.osgi.framework.console.CommandInterpreter;
+import org.eclipse.osgi.framework.console.CommandProvider;
+import org.opendaylight.controller.clustering.services.CacheConfigException;
+import org.opendaylight.controller.clustering.services.CacheExistException;
+import org.opendaylight.controller.clustering.services.IClusterContainerServices;
+import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.configuration.IConfigurationContainerAware;
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.core.Edge;
+import org.opendaylight.controller.sal.core.Host;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.core.Property;
+import org.opendaylight.controller.sal.core.TimeStamp;
+import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.topology.IListenTopoUpdates;
+import org.opendaylight.controller.sal.topology.ITopologyService;
+import org.opendaylight.controller.sal.utils.StatusCode;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.HexEncode;
+import org.opendaylight.controller.sal.utils.IObjectReader;
+import org.opendaylight.controller.sal.utils.ObjectReader;
+import org.opendaylight.controller.sal.utils.ObjectWriter;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.topologymanager.ITopologyManager;
+import org.opendaylight.controller.topologymanager.ITopologyManagerAware;
+import org.opendaylight.controller.topologymanager.TopologyUserLinkConfig;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The class describes TopologyManager which is the central repository of the
+ * network topology. It provides service for applications to interact with
+ * topology database and notifies all the listeners of topology changes.
+ */
+public class TopologyManagerImpl implements ITopologyManager,
+ IConfigurationContainerAware, IListenTopoUpdates, IObjectReader,
+ CommandProvider {
+ private static final Logger log = LoggerFactory
+ .getLogger(TopologyManagerImpl.class);
+ private ITopologyService topoService = null;
+ private IClusterContainerServices clusterContainerService = null;
+ // DB of all the Edges with properties which constitute our topology
+ private ConcurrentMap<Edge, Set<Property>> edgesDB = null;
+ // DB of all NodeConnector which are part of Edges, meaning they
+ // are connected to another NodeConnector on the other side
+ private ConcurrentMap<NodeConnector, Set<Property>> nodeConnectorsDB = null;
+ // DB of all the NodeConnectors with an Host attached to it
+ private ConcurrentMap<NodeConnector, ImmutablePair<Host, Set<Property>>> hostsDB = null;
+ // Topology Manager Aware listeners
+ private Set<ITopologyManagerAware> topologyManagerAware = Collections
+ .synchronizedSet(new HashSet<ITopologyManagerAware>());
+
+ private static String ROOT = GlobalConstants.STARTUPHOME.toString();
+ private String userLinksFileName = null;
+ private ConcurrentMap<String, TopologyUserLinkConfig> userLinks;
+
+ void nonClusterObjectCreate() {
+ edgesDB = new ConcurrentHashMap<Edge, Set<Property>>();
+ hostsDB = new ConcurrentHashMap<NodeConnector, ImmutablePair<Host, Set<Property>>>();
+ userLinks = new ConcurrentHashMap<String, TopologyUserLinkConfig>();
+ nodeConnectorsDB = new ConcurrentHashMap<NodeConnector, Set<Property>>();
+ }
+
+
+ void setTopologyManagerAware(ITopologyManagerAware s) {
+ if (this.topologyManagerAware != null) {
+ this.topologyManagerAware.add(s);
+ }
+ }
+
+ void unsetTopologyManagerAware(ITopologyManagerAware s) {
+ if (this.topologyManagerAware != null) {
+ this.topologyManagerAware.remove(s);
+ }
+ }
+
+ void setTopoService(ITopologyService s) {
+ this.topoService = s;
+ }
+
+ void unsetTopoService(ITopologyService s) {
+ if (this.topoService == s) {
+ this.topoService = null;
+ }
+ }
+
+ void setClusterContainerService(IClusterContainerServices s) {
+ log.debug("Cluster Service set");
+ this.clusterContainerService = s;
+ }
+
+ void unsetClusterContainerService(IClusterContainerServices s) {
+ if (this.clusterContainerService == s) {
+ log.debug("Cluster Service removed!");
+ this.clusterContainerService = null;
+ }
+ }
+
+ /**
+ * Function called by the dependency manager when all the required
+ * dependencies are satisfied
+ *
+ */
+ void init(Component c) {
+ String containerName = null;
+ Dictionary props = c.getServiceProperties();
+ if (props != null) {
+ containerName = (String) props.get("containerName");
+ } else {
+ // In the Global instance case the containerName is empty
+ containerName = "UNKNOWN";
+ }
+
+ if (this.clusterContainerService == null) {
+ log.error("Cluster Services is null, not expected!");
+ return;
+ }
+
+ if (this.topoService == null) {
+ log.error("Topology Services is null, not expected!");
+ return;
+ }
+
+ try {
+ this.edgesDB = (ConcurrentMap<Edge, Set<Property>>) this.clusterContainerService
+ .createCache("topologymanager.edgesDB", EnumSet
+ .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+ } catch (CacheExistException cee) {
+ log.error("topologymanager.edgesDB Cache already exists - "
+ + "destroy and recreate if needed");
+ } catch (CacheConfigException cce) {
+ log.error("topologymanager.edgesDB Cache configuration invalid - "
+ + "check cache mode");
+ }
+
+ try {
+ this.hostsDB = (ConcurrentMap<NodeConnector, ImmutablePair<Host, Set<Property>>>) this.clusterContainerService
+ .createCache("topologymanager.hostsDB", EnumSet
+ .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+ } catch (CacheExistException cee) {
+ log.error("topologymanager.hostsDB Cache already exists - "
+ + "destroy and recreate if needed");
+ } catch (CacheConfigException cce) {
+ log.error("topologymanager.hostsDB Cache configuration invalid - "
+ + "check cache mode");
+ }
+
+ try {
+ this.nodeConnectorsDB = (ConcurrentMap<NodeConnector, Set<Property>>) this.clusterContainerService
+ .createCache("topologymanager.nodeConnectorDB", EnumSet
+ .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+ } catch (CacheExistException cee) {
+ log.error("topologymanager.nodeConnectorDB Cache already exists"
+ + " - destroy and recreate if needed");
+ } catch (CacheConfigException cce) {
+ log.error("topologymanager.nodeConnectorDB Cache configuration "
+ + "invalid - check cache mode");
+ }
+
+ userLinks = new ConcurrentHashMap<String, TopologyUserLinkConfig>();
+
+ userLinksFileName = ROOT + "userTopology_" + containerName + ".conf";
+ registerWithOSGIConsole();
+ loadConfiguration();
+ }
+
+ /**
+ * Function called after the topology manager has registered the
+ * service in OSGi service registry.
+ *
+ */
+ void started() {
+ // SollicitRefresh MUST be called here else if called at init
+ // time it may sollicit refresh too soon.
+ log.debug("Sollicit topology refresh");
+ topoService.sollicitRefresh();
+ }
+
+ /**
+ * Function called by the dependency manager when at least one
+ * dependency become unsatisfied or when the component is shutting
+ * down because for example bundle is being stopped.
+ *
+ */
+ void destroy() {
+ if (this.clusterContainerService == null) {
+ log.error("Cluster Services is null, not expected!");
+ this.edgesDB = null;
+ this.hostsDB = null;
+ this.nodeConnectorsDB = null;
+ return;
+ }
+ this.clusterContainerService.destroyCache("topologymanager.edgesDB");
+ this.edgesDB = null;
+ this.clusterContainerService.destroyCache("topologymanager.hostsDB");
+ this.hostsDB = null;
+ this.clusterContainerService
+ .destroyCache("topologymanager.nodeConnectorDB");
+ this.nodeConnectorsDB = null;
+ log.debug("Topology Manager DB DE-allocated");
+ }
+
+ @SuppressWarnings("unchecked")
+ private void loadConfiguration() {
+ ObjectReader objReader = new ObjectReader();
+ ConcurrentMap<String, TopologyUserLinkConfig> confList = (ConcurrentMap<String, TopologyUserLinkConfig>) objReader
+ .read(this, userLinksFileName);
+
+ if (confList == null) {
+ return;
+ }
+
+ for (TopologyUserLinkConfig conf : confList.values()) {
+ addUserLink(conf);
+ }
+ }
+
+ @Override
+ public Status saveConfig() {
+ // Publish the save config event to the cluster nodes
+ /**
+ * Get the CLUSTERING SERVICES WORKING BEFORE TRYING THIS
+
+ configSaveEvent.put(new Date().getTime(), SAVE);
+ */
+ return saveConfigInternal();
+ }
+
+ public Status saveConfigInternal() {
+ Status retS;
+ ObjectWriter objWriter = new ObjectWriter();
+
+ retS = objWriter.write(
+ new ConcurrentHashMap<String, TopologyUserLinkConfig>(
+ userLinks), userLinksFileName);
+
+ if (retS.isSuccess()) {
+ return retS;
+ } else {
+ return new Status(StatusCode.INTERNALERROR, "Save failed");
+ }
+ }
+
+ @Override
+ public Map<Node, Set<Edge>> getNodeEdges() {
+ if (this.edgesDB == null) {
+ return null;
+ }
+
+ HashMap<Node, Set<Edge>> res = new HashMap<Node, Set<Edge>>();
+ for (Edge key : this.edgesDB.keySet()) {
+ // Lets analyze the tail
+ Node node = key.getTailNodeConnector().getNode();
+ Set<Edge> nodeEdges = res.get(node);
+ if (nodeEdges == null) {
+ nodeEdges = new HashSet<Edge>();
+ }
+ nodeEdges.add(key);
+ // We need to re-add to the MAP even if the element was
+ // already there so in case of clustered services the map
+ // gets updated in the cluster
+ res.put(node, nodeEdges);
+
+ // Lets analyze the head
+ node = key.getHeadNodeConnector().getNode();
+ nodeEdges = res.get(node);
+ if (nodeEdges == null) {
+ nodeEdges = new HashSet<Edge>();
+ }
+ nodeEdges.add(key);
+ // We need to re-add to the MAP even if the element was
+ // already there so in case of clustered services the map
+ // gets updated in the cluster
+ res.put(node, nodeEdges);
+ }
+
+ return res;
+ }
+
+ @Override
+ public boolean isInternal(NodeConnector p) {
+ if (this.nodeConnectorsDB == null) {
+ return false;
+ }
+
+ // This is an internal NodeConnector if is connected to
+ // another Node i.e it's part of the nodeConnectorsDB
+ return (this.nodeConnectorsDB.get(p) != null);
+ }
+
+ /**
+ * The Map returned is a copy of the current topology hence if the
+ * topology changes the copy doesn't
+ *
+ * @return A Map representing the current topology expressed as
+ * edges of the network
+ */
+ @Override
+ public Map<Edge, Set<Property>> getEdges() {
+ if (this.edgesDB == null) {
+ return null;
+ }
+
+ HashMap<Edge, Set<Property>> res = new HashMap<Edge, Set<Property>>();
+ for (Edge key : this.edgesDB.keySet()) {
+ // Sets of props are copied because the composition of
+ // those properties could change with time
+ HashSet<Property> prop = new HashSet<Property>(this.edgesDB
+ .get(key));
+ // We can simply reuse the key because the object is
+ // immutable so doesn't really matter that we are
+ // referencing the only owned by a different table, the
+ // meaning is the same because doesn't change with time.
+ res.put(key, prop);
+ }
+
+ return res;
+ }
+
+ // TODO remove with spring-dm removal
+ /**
+ * @param set the topologyAware to set
+ */
+ public void setTopologyAware(Set<Object> set) {
+ for (Object s : set) {
+ setTopologyManagerAware((ITopologyManagerAware) s);
+ }
+ }
+
+ @Override
+ public Set<NodeConnector> getNodeConnectorWithHost() {
+ if (this.hostsDB == null) {
+ return null;
+ }
+
+ return (this.hostsDB.keySet());
+ }
+
+ @Override
+ public Map<Node, Set<NodeConnector>> getNodesWithNodeConnectorHost() {
+ if (this.hostsDB == null) {
+ return null;
+ }
+ HashMap<Node, Set<NodeConnector>> res = new HashMap<Node, Set<NodeConnector>>();
+
+ for (NodeConnector p : this.hostsDB.keySet()) {
+ Node n = p.getNode();
+ Set<NodeConnector> pSet = res.get(n);
+ if (pSet == null) {
+ // Create the HashSet if null
+ pSet = new HashSet<NodeConnector>();
+ res.put(n, pSet);
+ }
+
+ // Keep updating the HashSet, given this is not a
+ // clustered map we can just update the set without
+ // worrying to update the hashmap.
+ pSet.add(p);
+ }
+
+ return (res);
+ }
+
+ @Override
+ public Host getHostAttachedToNodeConnector(NodeConnector p) {
+ if (this.hostsDB == null) {
+ return null;
+ }
+
+ return (this.hostsDB.get(p).getLeft());
+ }
+
+ @Override
+ public void updateHostLink(NodeConnector p, Host h, UpdateType t,
+ Set<Property> props) {
+ if (this.hostsDB == null) {
+ return;
+ }
+
+ switch (t) {
+ case ADDED:
+ case CHANGED:
+ // Clone the property set in case non null else just
+ // create an empty one. Caches allocated via infinispan
+ // don't allow null values
+ if (props == null) {
+ props = new HashSet<Property>();
+ } else {
+ props = new HashSet<Property>(props);
+ }
+
+ this.hostsDB.put(p, new ImmutablePair(h, props));
+ break;
+ case REMOVED:
+ this.hostsDB.remove(p);
+ break;
+ }
+ }
+
+ @Override
+ public void edgeUpdate(Edge e, UpdateType type, Set<Property> props) {
+ switch (type) {
+ case ADDED:
+ // Make sure the props are non-null
+ if (props == null) {
+ props = (Set<Property>) new HashSet();
+ } else {
+ // Copy the set so noone is going to change the content
+ props = (Set<Property>) new HashSet(props);
+ }
+
+ // Now make sure thre is the creation timestamp for the
+ // edge, if not there timestamp with the first update
+ boolean found_create = false;
+ for (Property prop : props) {
+ if (prop instanceof TimeStamp) {
+ TimeStamp t = (TimeStamp) prop;
+ if (t.getTimeStampName().equals("creation")) {
+ found_create = true;
+ }
+ }
+ }
+
+ if (!found_create) {
+ TimeStamp t = new TimeStamp(System.currentTimeMillis(),
+ "creation");
+ props.add(t);
+ }
+
+ // Now add this in the database eventually overriding
+ // something that may have been already existing
+ this.edgesDB.put(e, props);
+
+ // Now populate the DB of NodeConnectors
+ // NOTE WELL: properties are empy sets, not really needed
+ // for now.
+ this.nodeConnectorsDB.put(e.getHeadNodeConnector(),
+ new HashSet<Property>());
+ this.nodeConnectorsDB.put(e.getTailNodeConnector(),
+ new HashSet<Property>());
+ break;
+ case REMOVED:
+ // Now remove the edge from edgesDB
+ this.edgesDB.remove(e);
+
+ // Now lets update the NodeConnectors DB, the assumption
+ // here is that two NodeConnector are exclusively
+ // connected by 1 and only 1 edge, this is reasonable in
+ // the same plug (virtual of phisical) we can assume two
+ // cables won't be plugged. This could break only in case
+ // of devices in the middle that acts as hubs, but it
+ // should be safe to assume that won't happen.
+ this.nodeConnectorsDB.remove(e.getHeadNodeConnector());
+ this.nodeConnectorsDB.remove(e.getTailNodeConnector());
+ break;
+ case CHANGED:
+ Set<Property> old_props = this.edgesDB.get(e);
+
+ // When property changes lets make sure we can change it
+ // all except the creation time stamp because that should
+ // be changed only when the edge is destroyed and created
+ // again
+ TimeStamp tc = null;
+ for (Property prop : old_props) {
+ if (prop instanceof TimeStamp) {
+ TimeStamp t = (TimeStamp) prop;
+ if (t.getTimeStampName().equals("creation")) {
+ tc = t;
+ }
+ }
+ }
+
+ // Now lest make sure new properties are non-null
+ // Make sure the props are non-null
+ if (props == null) {
+ props = (Set<Property>) new HashSet();
+ } else {
+ // Copy the set so noone is going to change the content
+ props = (Set<Property>) new HashSet(props);
+ }
+
+ // Now lets remove the creation property if exist in the
+ // new props
+ for (Iterator<Property> i = props.iterator(); i.hasNext();) {
+ Property prop = i.next();
+ if (prop instanceof TimeStamp) {
+ TimeStamp t = (TimeStamp) prop;
+ if (t.getTimeStampName().equals("creation")) {
+ i.remove();
+ }
+ }
+ }
+
+ // Now lets add the creation timestamp in it
+ if (tc != null) {
+ props.add(tc);
+ }
+
+ // Finally update
+ this.edgesDB.put(e, props);
+ break;
+ }
+
+ // Now update the listeners
+ for (ITopologyManagerAware s : this.topologyManagerAware) {
+ try {
+ s.edgeUpdate(e, type, props);
+ } catch (Exception exc) {
+ log.error("Exception on callback", exc);
+ }
+ }
+ }
+
+ private Edge getReverseLinkTuple(TopologyUserLinkConfig link) {
+ TopologyUserLinkConfig rLink = new TopologyUserLinkConfig(link
+ .getName(), link.getDstSwitchId(), link.getDstPort(), link
+ .getSrcSwitchId(), link.getSrcPort());
+ return getLinkTuple(rLink);
+ }
+
+ private Edge getLinkTuple(TopologyUserLinkConfig link) {
+ Edge linkTuple = null;
+ Long sID = link.getSrcSwitchIDLong();
+ Long dID = link.getDstSwitchIDLong();
+ Short srcPort = Short.valueOf((short) 0);
+ Short dstPort = Short.valueOf((short) 0);
+ if (link.isSrcPortByName()) {
+ // TODO find the inventory service to do this, for now 0
+ //srcPort = srcSw.getPortNumber(link.getSrcPort());
+ } else {
+ srcPort = Short.parseShort(link.getSrcPort());
+ }
+
+ if (link.isDstPortByName()) {
+ //dstPort = dstSw.getPortNumber(link.getDstPort());;
+ } else {
+ dstPort = Short.parseShort(link.getDstPort());
+ }
+
+ // if atleast 1 link exists for the srcPort and atleast 1 link exists for the dstPort
+ // that makes it ineligible for the Manual link addition
+ // This is just an extra protection to avoid mis-programming.
+ boolean srcLinkExists = false;
+ boolean dstLinkExists = false;
+ /**
+ * Disabling this optimization for now to understand the real benefit of doing this.
+ * Since this is a Manual Link addition, the user knows what he is doing and it is
+ * not good to restrict such creativity...
+ */
+ /*
+ Set <Edge> links = oneTopology.getLinks().keySet();
+ if (links != null) {
+ for (Edge eLink : links) {
+ if (!eLink.isUserCreated() &&
+ eLink.getSrc().getSid().equals(link.getSrcSwitchIDLong()) &&
+ eLink.getSrc().getPort().equals(srcPort)) {
+ srcLinkExists = true;
+ }
+
+ if (!eLink.isUserCreated() &&
+ eLink.getSrc().getSid().equals(link.getSrcSwitchIDLong()) &&
+ eLink.getSrc().getPort().equals(srcPort)) {
+ dstLinkExists = true;
+ }
+
+ if (!eLink.isUserCreated() &&
+ eLink.getDst().getSid().equals(link.getSrcSwitchIDLong()) &&
+ eLink.getDst().getPort().equals(srcPort)) {
+ srcLinkExists = true;
+ }
+
+ if (!eLink.isUserCreated() &&
+ eLink.getDst().getSid().equals(link.getSrcSwitchIDLong()) &&
+ eLink.getDst().getPort().equals(srcPort)) {
+ dstLinkExists = true;
+ }
+ }
+ }
+ */
+ //TODO check a way to validate the port with inventory services
+ //if (srcSw.getPorts().contains(srcPort) &&
+ //dstSw.getPorts().contains(srcPort) &&
+ if (!srcLinkExists && !dstLinkExists) {
+ Node sNode = null;
+ Node dNode = null;
+ NodeConnector sPort = null;
+ NodeConnector dPort = null;
+ linkTuple = null;
+ try {
+ sNode = new Node(Node.NodeIDType.OPENFLOW, sID);
+ dNode = new Node(Node.NodeIDType.OPENFLOW, dID);
+ sPort = new NodeConnector(
+ NodeConnector.NodeConnectorIDType.OPENFLOW, srcPort,
+ sNode);
+ dPort = new NodeConnector(
+ NodeConnector.NodeConnectorIDType.OPENFLOW, dstPort,
+ dNode);
+ linkTuple = new Edge(sPort, dPort);
+ } catch (ConstructionException cex) {
+ }
+ return linkTuple;
+ }
+
+ if (srcLinkExists && dstLinkExists) {
+ link.setStatus(TopologyUserLinkConfig.STATUS.INCORRECT);
+ }
+ return null;
+ }
+
+ @Override
+ public ConcurrentMap<String, TopologyUserLinkConfig> getUserLinks() {
+ return userLinks;
+ }
+
+ @Override
+ public Status addUserLink(TopologyUserLinkConfig link) {
+ if (!link.isValid()) {
+ return new Status(StatusCode.BADREQUEST,
+ "Configuration Invalid. Please check the parameters");
+ }
+ if (userLinks.get(link.getName()) != null) {
+ return new Status(StatusCode.CONFLICT,
+ "Link with name : " + link.getName()
+ + " already exists. Please use another name");
+ }
+ if (userLinks.containsValue(link)) {
+ return new Status(StatusCode.CONFLICT, "Link configuration exists");
+ }
+
+ link.setStatus(TopologyUserLinkConfig.STATUS.LINKDOWN);
+ userLinks.put(link.getName(), link);
+
+ Edge linkTuple = getLinkTuple(link);
+ if (linkTuple != null) {
+ try {
+ // TODO The onetopology will be gone too, topology
+ //manager is the master of the topology at this point
+ //if (oneTopology.addUserConfiguredLink(linkTuple)) {
+ linkTuple = getReverseLinkTuple(link);
+ //if (oneTopology.addUserConfiguredLink(linkTuple)) {
+ link.setStatus(TopologyUserLinkConfig.STATUS.SUCCESS);
+ //}
+ //}
+ } catch (Exception e) {
+ return new Status(StatusCode.INTERNALERROR,
+ "Exception while adding custom link : " +
+ e.getMessage());
+ }
+ }
+ return new Status(StatusCode.SUCCESS, null);
+ }
+
+ @Override
+ public Status deleteUserLink(String linkName) {
+ if (linkName == null) {
+ return new Status(StatusCode.BADREQUEST,
+ "A valid linkName is required to Delete a link");
+ }
+
+ TopologyUserLinkConfig link = userLinks.get(linkName);
+
+ Edge linkTuple = getLinkTuple(link);
+ userLinks.remove(linkName);
+ if (linkTuple != null) {
+ try {
+ //oneTopology.deleteUserConfiguredLink(linkTuple);
+ } catch (Exception e) {
+ log
+ .warn("Harmless : Exception while Deleting User Configured link "
+ + link + " " + e.toString());
+ }
+ linkTuple = getReverseLinkTuple(link);
+ try {
+ //oneTopology.deleteUserConfiguredLink(linkTuple);
+ } catch (Exception e) {
+ log
+ .error("Harmless : Exception while Deleting User Configured Reverse link "
+ + link + " " + e.toString());
+ }
+ }
+ return new Status(StatusCode.SUCCESS, null);
+ }
+
+ private void registerWithOSGIConsole() {
+ BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
+ .getBundleContext();
+ bundleContext.registerService(CommandProvider.class.getName(), this,
+ null);
+ }
+
+ @Override
+ public String getHelp() {
+ StringBuffer help = new StringBuffer();
+ help.append("---Topology Manager---\n");
+ help
+ .append("\t addTopo name <src-sw-id> <port-number> <dst-sw-id> <port-number>\n");
+ help.append("\t delTopo name\n");
+ help.append("\t _printTopo\n");
+ return help.toString();
+ }
+
+ public void _printTopo(CommandInterpreter ci) {
+ for (String name : this.userLinks.keySet()) {
+ ci.println(name + " : " + userLinks.get(name));
+ }
+ }
+
+ public void _addTopo(CommandInterpreter ci) {
+ String name = ci.nextArgument();
+ if ((name == null)) {
+ ci.println("Please enter a valid Name");
+ return;
+ }
+
+ String dpid = ci.nextArgument();
+ if (dpid == null) {
+ ci.println("Invalid Switch ID. Format xx:xx:xx:xx:xx:xx:xx:xx");
+ return;
+ }
+ try {
+ HexEncode.stringToLong(dpid);
+ } catch (Exception e) {
+ ci.println("Invalid Switch ID. Format xx:xx:xx:xx:xx:xx:xx:xx");
+ return;
+ }
+
+ String port = ci.nextArgument();
+ if (port == null) {
+ ci.println("Invalid port number");
+ return;
+ }
+
+ String ddpid = ci.nextArgument();
+ if (ddpid == null) {
+ ci.println("Invalid Switch ID. Format xx:xx:xx:xx:xx:xx:xx:xx");
+ return;
+ }
+ try {
+ HexEncode.stringToLong(ddpid);
+ } catch (Exception e) {
+ ci.println("Invalid Switch ID. Format xx:xx:xx:xx:xx:xx:xx:xx");
+ return;
+ }
+
+ String dport = ci.nextArgument();
+ if (dport == null) {
+ ci.println("Invalid port number");
+ return;
+ }
+ TopologyUserLinkConfig config = new TopologyUserLinkConfig(name,
+ dpid, port, ddpid, dport);
+ ci.println(this.addUserLink(config));
+ }
+
+ public void _delTopo(CommandInterpreter ci) {
+ String name = ci.nextArgument();
+ if ((name == null)) {
+ ci.println("Please enter a valid Name");
+ return;
+ }
+ this.deleteUserLink(name);
+ }
+
+ @Override
+ public Object readObject(ObjectInputStream ois)
+ throws FileNotFoundException, IOException, ClassNotFoundException {
+ // TODO Auto-generated method stub
+ return ois.readObject();
+ }
+
+ @Override
+ public Status saveConfiguration() {
+ return saveConfig();
+ }
+
+ @Override
+ public void edgeOverUtilized(Edge edge) {
+ log.warn("Link Utilization above normal: " + edge);
+ }
+
+ @Override
+ public void edgeUtilBackToNormal(Edge edge) {
+ log.warn("Link Utilization back to normal: " + edge);
+ }
+
+}