3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
10 package org.opendaylight.controller.topologymanager.internal;
12 import java.io.FileNotFoundException;
13 import java.io.IOException;
14 import java.io.ObjectInputStream;
15 import java.util.Collections;
16 import java.util.Dictionary;
17 import java.util.EnumSet;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.Iterator;
23 import java.util.concurrent.ConcurrentHashMap;
24 import java.util.concurrent.ConcurrentMap;
26 import org.apache.commons.lang3.tuple.ImmutablePair;
27 import org.apache.felix.dm.Component;
28 import org.eclipse.osgi.framework.console.CommandInterpreter;
29 import org.eclipse.osgi.framework.console.CommandProvider;
30 import org.opendaylight.controller.clustering.services.CacheConfigException;
31 import org.opendaylight.controller.clustering.services.CacheExistException;
32 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
33 import org.opendaylight.controller.clustering.services.IClusterServices;
34 import org.opendaylight.controller.configuration.IConfigurationContainerAware;
35 import org.opendaylight.controller.sal.core.ConstructionException;
36 import org.opendaylight.controller.sal.core.Edge;
37 import org.opendaylight.controller.sal.core.Host;
38 import org.opendaylight.controller.sal.core.Node;
39 import org.opendaylight.controller.sal.core.NodeConnector;
40 import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
41 import org.opendaylight.controller.sal.core.Property;
42 import org.opendaylight.controller.sal.core.TimeStamp;
43 import org.opendaylight.controller.sal.core.UpdateType;
44 import org.opendaylight.controller.sal.core.Node.NodeIDType;
45 import org.opendaylight.controller.sal.topology.IListenTopoUpdates;
46 import org.opendaylight.controller.sal.topology.ITopologyService;
47 import org.opendaylight.controller.sal.utils.StatusCode;
48 import org.opendaylight.controller.sal.utils.GlobalConstants;
49 import org.opendaylight.controller.sal.utils.IObjectReader;
50 import org.opendaylight.controller.sal.utils.ObjectReader;
51 import org.opendaylight.controller.sal.utils.ObjectWriter;
52 import org.opendaylight.controller.sal.utils.Status;
53 import org.opendaylight.controller.topologymanager.ITopologyManager;
54 import org.opendaylight.controller.topologymanager.ITopologyManagerAware;
55 import org.opendaylight.controller.topologymanager.TopologyUserLinkConfig;
56 import org.osgi.framework.BundleContext;
57 import org.osgi.framework.FrameworkUtil;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
62 * The class describes TopologyManager which is the central repository of the
63 * network topology. It provides service for applications to interact with
64 * topology database and notifies all the listeners of topology changes.
66 public class TopologyManagerImpl implements ITopologyManager,
67 IConfigurationContainerAware, IListenTopoUpdates, IObjectReader,
69 private static final Logger log = LoggerFactory
70 .getLogger(TopologyManagerImpl.class);
71 private ITopologyService topoService = null;
72 private IClusterContainerServices clusterContainerService = null;
73 // DB of all the Edges with properties which constitute our topology
74 private ConcurrentMap<Edge, Set<Property>> edgesDB = null;
75 // DB of all NodeConnector which are part of Edges, meaning they
76 // are connected to another NodeConnector on the other side
77 private ConcurrentMap<NodeConnector, Set<Property>> nodeConnectorsDB = null;
78 // DB of all the NodeConnectors with an Host attached to it
79 private ConcurrentMap<NodeConnector, ImmutablePair<Host, Set<Property>>> hostsDB = null;
80 // Topology Manager Aware listeners
81 private Set<ITopologyManagerAware> topologyManagerAware = Collections
82 .synchronizedSet(new HashSet<ITopologyManagerAware>());
84 private static String ROOT = GlobalConstants.STARTUPHOME.toString();
85 private String userLinksFileName = null;
86 private ConcurrentMap<String, TopologyUserLinkConfig> userLinks;
88 void nonClusterObjectCreate() {
89 edgesDB = new ConcurrentHashMap<Edge, Set<Property>>();
90 hostsDB = new ConcurrentHashMap<NodeConnector, ImmutablePair<Host, Set<Property>>>();
91 userLinks = new ConcurrentHashMap<String, TopologyUserLinkConfig>();
92 nodeConnectorsDB = new ConcurrentHashMap<NodeConnector, Set<Property>>();
96 void setTopologyManagerAware(ITopologyManagerAware s) {
97 if (this.topologyManagerAware != null) {
98 log.debug("Adding ITopologyManagerAware: {}", s);
99 this.topologyManagerAware.add(s);
103 void unsetTopologyManagerAware(ITopologyManagerAware s) {
104 if (this.topologyManagerAware != null) {
105 log.debug("Removing ITopologyManagerAware: {}", s);
106 this.topologyManagerAware.remove(s);
110 void setTopoService(ITopologyService s) {
111 log.debug("Adding ITopologyService: {}", s);
112 this.topoService = s;
115 void unsetTopoService(ITopologyService s) {
116 if (this.topoService == s) {
117 log.debug("Removing ITopologyService: {}", s);
118 this.topoService = null;
122 void setClusterContainerService(IClusterContainerServices s) {
123 log.debug("Cluster Service set");
124 this.clusterContainerService = s;
127 void unsetClusterContainerService(IClusterContainerServices s) {
128 if (this.clusterContainerService == s) {
129 log.debug("Cluster Service removed!");
130 this.clusterContainerService = null;
135 * Function called by the dependency manager when all the required
136 * dependencies are satisfied
139 void init(Component c) {
140 String containerName = null;
141 Dictionary props = c.getServiceProperties();
143 containerName = (String) props.get("containerName");
145 // In the Global instance case the containerName is empty
146 containerName = "UNKNOWN";
149 if (this.clusterContainerService == null) {
150 log.error("Cluster Services is null, not expected!");
154 if (this.topoService == null) {
155 log.error("Topology Services is null, not expected!");
160 this.edgesDB = (ConcurrentMap<Edge, Set<Property>>) this.clusterContainerService
161 .createCache("topologymanager.edgesDB", EnumSet
162 .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
163 } catch (CacheExistException cee) {
164 log.error("topologymanager.edgesDB Cache already exists - "
165 + "destroy and recreate if needed");
166 } catch (CacheConfigException cce) {
167 log.error("topologymanager.edgesDB Cache configuration invalid - "
168 + "check cache mode");
172 this.hostsDB = (ConcurrentMap<NodeConnector, ImmutablePair<Host, Set<Property>>>) this.clusterContainerService
173 .createCache("topologymanager.hostsDB", EnumSet
174 .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
175 } catch (CacheExistException cee) {
176 log.error("topologymanager.hostsDB Cache already exists - "
177 + "destroy and recreate if needed");
178 } catch (CacheConfigException cce) {
179 log.error("topologymanager.hostsDB Cache configuration invalid - "
180 + "check cache mode");
184 this.nodeConnectorsDB = (ConcurrentMap<NodeConnector, Set<Property>>) this.clusterContainerService
185 .createCache("topologymanager.nodeConnectorDB", EnumSet
186 .of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
187 } catch (CacheExistException cee) {
188 log.error("topologymanager.nodeConnectorDB Cache already exists"
189 + " - destroy and recreate if needed");
190 } catch (CacheConfigException cce) {
191 log.error("topologymanager.nodeConnectorDB Cache configuration "
192 + "invalid - check cache mode");
195 userLinks = new ConcurrentHashMap<String, TopologyUserLinkConfig>();
197 userLinksFileName = ROOT + "userTopology_" + containerName + ".conf";
198 registerWithOSGIConsole();
203 * Function called after the topology manager has registered the
204 * service in OSGi service registry.
208 // SollicitRefresh MUST be called here else if called at init
209 // time it may sollicit refresh too soon.
210 log.debug("Sollicit topology refresh");
211 topoService.sollicitRefresh();
215 * Function called by the dependency manager when at least one
216 * dependency become unsatisfied or when the component is shutting
217 * down because for example bundle is being stopped.
221 if (this.clusterContainerService == null) {
222 log.error("Cluster Services is null, not expected!");
225 this.nodeConnectorsDB = null;
228 this.clusterContainerService.destroyCache("topologymanager.edgesDB");
230 this.clusterContainerService.destroyCache("topologymanager.hostsDB");
232 this.clusterContainerService
233 .destroyCache("topologymanager.nodeConnectorDB");
234 this.nodeConnectorsDB = null;
235 log.debug("Topology Manager DB Deallocated");
238 @SuppressWarnings("unchecked")
239 private void loadConfiguration() {
240 ObjectReader objReader = new ObjectReader();
241 ConcurrentMap<String, TopologyUserLinkConfig> confList = (ConcurrentMap<String, TopologyUserLinkConfig>) objReader
242 .read(this, userLinksFileName);
244 if (confList == null) {
248 for (TopologyUserLinkConfig conf : confList.values()) {
254 public Status saveConfig() {
255 // Publish the save config event to the cluster nodes
257 * Get the CLUSTERING SERVICES WORKING BEFORE TRYING THIS
259 configSaveEvent.put(new Date().getTime(), SAVE);
261 return saveConfigInternal();
264 public Status saveConfigInternal() {
266 ObjectWriter objWriter = new ObjectWriter();
268 retS = objWriter.write(
269 new ConcurrentHashMap<String, TopologyUserLinkConfig>(
270 userLinks), userLinksFileName);
272 if (retS.isSuccess()) {
275 return new Status(StatusCode.INTERNALERROR, "Save failed");
280 public Map<Node, Set<Edge>> getNodeEdges() {
281 if (this.edgesDB == null) {
285 HashMap<Node, Set<Edge>> res = new HashMap<Node, Set<Edge>>();
286 for (Edge key : this.edgesDB.keySet()) {
287 // Lets analyze the tail
288 Node node = key.getTailNodeConnector().getNode();
289 Set<Edge> nodeEdges = res.get(node);
290 if (nodeEdges == null) {
291 nodeEdges = new HashSet<Edge>();
294 // We need to re-add to the MAP even if the element was
295 // already there so in case of clustered services the map
296 // gets updated in the cluster
297 res.put(node, nodeEdges);
299 // Lets analyze the head
300 node = key.getHeadNodeConnector().getNode();
301 nodeEdges = res.get(node);
302 if (nodeEdges == null) {
303 nodeEdges = new HashSet<Edge>();
306 // We need to re-add to the MAP even if the element was
307 // already there so in case of clustered services the map
308 // gets updated in the cluster
309 res.put(node, nodeEdges);
316 public boolean isInternal(NodeConnector p) {
317 if (this.nodeConnectorsDB == null) {
321 // This is an internal NodeConnector if is connected to
322 // another Node i.e it's part of the nodeConnectorsDB
323 return (this.nodeConnectorsDB.get(p) != null);
327 * The Map returned is a copy of the current topology hence if the
328 * topology changes the copy doesn't
330 * @return A Map representing the current topology expressed as
331 * edges of the network
334 public Map<Edge, Set<Property>> getEdges() {
335 if (this.edgesDB == null) {
339 HashMap<Edge, Set<Property>> res = new HashMap<Edge, Set<Property>>();
340 for (Edge key : this.edgesDB.keySet()) {
341 // Sets of props are copied because the composition of
342 // those properties could change with time
343 HashSet<Property> prop = new HashSet<Property>(this.edgesDB
345 // We can simply reuse the key because the object is
346 // immutable so doesn't really matter that we are
347 // referencing the only owned by a different table, the
348 // meaning is the same because doesn't change with time.
355 // TODO remove with spring-dm removal
357 * @param set the topologyAware to set
359 public void setTopologyAware(Set<Object> set) {
360 for (Object s : set) {
361 setTopologyManagerAware((ITopologyManagerAware) s);
366 public Set<NodeConnector> getNodeConnectorWithHost() {
367 if (this.hostsDB == null) {
371 return (this.hostsDB.keySet());
375 public Map<Node, Set<NodeConnector>> getNodesWithNodeConnectorHost() {
376 if (this.hostsDB == null) {
379 HashMap<Node, Set<NodeConnector>> res = new HashMap<Node, Set<NodeConnector>>();
381 for (NodeConnector p : this.hostsDB.keySet()) {
382 Node n = p.getNode();
383 Set<NodeConnector> pSet = res.get(n);
385 // Create the HashSet if null
386 pSet = new HashSet<NodeConnector>();
390 // Keep updating the HashSet, given this is not a
391 // clustered map we can just update the set without
392 // worrying to update the hashmap.
400 public Host getHostAttachedToNodeConnector(NodeConnector p) {
401 if (this.hostsDB == null) {
405 return (this.hostsDB.get(p).getLeft());
409 public void updateHostLink(NodeConnector p, Host h, UpdateType t,
410 Set<Property> props) {
411 if (this.hostsDB == null) {
418 // Clone the property set in case non null else just
419 // create an empty one. Caches allocated via infinispan
420 // don't allow null values
422 props = new HashSet<Property>();
424 props = new HashSet<Property>(props);
427 this.hostsDB.put(p, new ImmutablePair(h, props));
430 this.hostsDB.remove(p);
436 public void edgeUpdate(Edge e, UpdateType type, Set<Property> props) {
439 // Make sure the props are non-null
441 props = (Set<Property>) new HashSet();
443 // Copy the set so noone is going to change the content
444 props = (Set<Property>) new HashSet(props);
447 // Now make sure thre is the creation timestamp for the
448 // edge, if not there timestamp with the first update
449 boolean found_create = false;
450 for (Property prop : props) {
451 if (prop instanceof TimeStamp) {
452 TimeStamp t = (TimeStamp) prop;
453 if (t.getTimeStampName().equals("creation")) {
460 TimeStamp t = new TimeStamp(System.currentTimeMillis(),
465 // Now add this in the database eventually overriding
466 // something that may have been already existing
467 this.edgesDB.put(e, props);
469 // Now populate the DB of NodeConnectors
470 // NOTE WELL: properties are empy sets, not really needed
472 this.nodeConnectorsDB.put(e.getHeadNodeConnector(),
473 new HashSet<Property>());
474 this.nodeConnectorsDB.put(e.getTailNodeConnector(),
475 new HashSet<Property>());
476 log.trace("Edge {} {}", e.toString(), type.name());
479 // Now remove the edge from edgesDB
480 this.edgesDB.remove(e);
482 // Now lets update the NodeConnectors DB, the assumption
483 // here is that two NodeConnector are exclusively
484 // connected by 1 and only 1 edge, this is reasonable in
485 // the same plug (virtual of phisical) we can assume two
486 // cables won't be plugged. This could break only in case
487 // of devices in the middle that acts as hubs, but it
488 // should be safe to assume that won't happen.
489 this.nodeConnectorsDB.remove(e.getHeadNodeConnector());
490 this.nodeConnectorsDB.remove(e.getTailNodeConnector());
491 log.trace("Edge {} {}", e.toString(), type.name());
494 Set<Property> old_props = this.edgesDB.get(e);
496 // When property changes lets make sure we can change it
497 // all except the creation time stamp because that should
498 // be changed only when the edge is destroyed and created
501 for (Property prop : old_props) {
502 if (prop instanceof TimeStamp) {
503 TimeStamp t = (TimeStamp) prop;
504 if (t.getTimeStampName().equals("creation")) {
510 // Now lest make sure new properties are non-null
511 // Make sure the props are non-null
513 props = (Set<Property>) new HashSet();
515 // Copy the set so noone is going to change the content
516 props = (Set<Property>) new HashSet(props);
519 // Now lets remove the creation property if exist in the
521 for (Iterator<Property> i = props.iterator(); i.hasNext();) {
522 Property prop = i.next();
523 if (prop instanceof TimeStamp) {
524 TimeStamp t = (TimeStamp) prop;
525 if (t.getTimeStampName().equals("creation")) {
531 // Now lets add the creation timestamp in it
537 this.edgesDB.put(e, props);
538 log.trace("Edge {} {}", e.toString(), type.name());
542 // Now update the listeners
543 for (ITopologyManagerAware s : this.topologyManagerAware) {
545 s.edgeUpdate(e, type, props);
546 } catch (Exception exc) {
547 log.error("Exception on callback", exc);
552 private Edge getReverseLinkTuple(TopologyUserLinkConfig link) {
553 TopologyUserLinkConfig rLink = new TopologyUserLinkConfig(
554 link.getName(), link.getDstNodeIDType(), link.getDstSwitchId(),
555 link.getDstNodeConnectorIDType(), link.getDstPort(),
556 link.getSrcNodeIDType(), link.getSrcSwitchId(),
557 link.getSrcNodeConnectorIDType(), link.getSrcPort());
558 return getLinkTuple(rLink);
561 private Edge getLinkTuple(TopologyUserLinkConfig link) {
562 Edge linkTuple = null;
564 // if atleast 1 link exists for the srcPort and atleast 1 link exists for the dstPort
565 // that makes it ineligible for the Manual link addition
566 // This is just an extra protection to avoid mis-programming.
567 boolean srcLinkExists = false;
568 boolean dstLinkExists = false;
569 //TODO check a way to validate the port with inventory services
570 //if (srcSw.getPorts().contains(srcPort) &&
571 //dstSw.getPorts().contains(srcPort) &&
572 if (!srcLinkExists && !dstLinkExists) {
575 NodeConnector sPort = null;
576 NodeConnector dPort = null;
578 String srcNodeIDType = link.getSrcNodeIDType();
579 String srcNodeConnectorIDType = link.getSrcNodeConnectorIDType();
580 String dstNodeIDType = link.getDstNodeIDType();
581 String dstNodeConnectorIDType = link.getDstNodeConnectorIDType();
583 if (srcNodeIDType.equals(NodeIDType.OPENFLOW)) {
584 sNode = new Node(srcNodeIDType, link.getSrcSwitchIDLong());
586 sNode = new Node(srcNodeIDType, link.getSrcSwitchId());
589 if (dstNodeIDType.equals(NodeIDType.OPENFLOW)) {
590 dNode = new Node(dstNodeIDType, link.getDstSwitchIDLong());
592 dNode = new Node(dstNodeIDType, link.getDstSwitchId());
595 if (srcNodeConnectorIDType.equals(NodeConnectorIDType.OPENFLOW)) {
596 Short srcPort = Short.valueOf((short) 0);
597 if (!link.isSrcPortByName()) {
598 srcPort = Short.parseShort(link.getSrcPort());
600 sPort = new NodeConnector(srcNodeConnectorIDType,
603 sPort = new NodeConnector(srcNodeConnectorIDType,
604 link.getSrcPort(), sNode);
607 if (dstNodeConnectorIDType.equals(NodeConnectorIDType.OPENFLOW)) {
608 Short dstPort = Short.valueOf((short) 0);
609 if (!link.isDstPortByName()) {
610 dstPort = Short.parseShort(link.getDstPort());
612 dPort = new NodeConnector(dstNodeConnectorIDType,
615 dPort = new NodeConnector(dstNodeConnectorIDType,
616 link.getDstPort(), dNode);
618 linkTuple = new Edge(sPort, dPort);
619 } catch (ConstructionException cex) {
620 log.warn("Caught exception ", cex);
625 if (srcLinkExists && dstLinkExists) {
626 link.setStatus(TopologyUserLinkConfig.STATUS.INCORRECT);
632 public ConcurrentMap<String, TopologyUserLinkConfig> getUserLinks() {
637 public Status addUserLink(TopologyUserLinkConfig link) {
638 if (!link.isValid()) {
639 return new Status(StatusCode.BADREQUEST,
640 "Configuration Invalid. Please check the parameters");
642 if (userLinks.get(link.getName()) != null) {
643 return new Status(StatusCode.CONFLICT,
644 "Link with name : " + link.getName()
645 + " already exists. Please use another name");
647 if (userLinks.containsValue(link)) {
648 return new Status(StatusCode.CONFLICT, "Link configuration exists");
651 link.setStatus(TopologyUserLinkConfig.STATUS.LINKDOWN);
652 userLinks.put(link.getName(), link);
654 Edge linkTuple = getLinkTuple(link);
655 if (linkTuple != null) {
657 linkTuple = getReverseLinkTuple(link);
658 link.setStatus(TopologyUserLinkConfig.STATUS.SUCCESS);
659 } catch (Exception e) {
660 return new Status(StatusCode.INTERNALERROR,
661 "Exception while adding custom link : " +
665 return new Status(StatusCode.SUCCESS, null);
669 public Status deleteUserLink(String linkName) {
670 if (linkName == null) {
671 return new Status(StatusCode.BADREQUEST,
672 "A valid linkName is required to Delete a link");
675 TopologyUserLinkConfig link = userLinks.get(linkName);
677 Edge linkTuple = getLinkTuple(link);
678 userLinks.remove(linkName);
679 if (linkTuple != null) {
681 //oneTopology.deleteUserConfiguredLink(linkTuple);
682 } catch (Exception e) {
684 .warn("Harmless : Exception while Deleting User Configured link {} {}",
687 linkTuple = getReverseLinkTuple(link);
689 //oneTopology.deleteUserConfiguredLink(linkTuple);
690 } catch (Exception e) {
692 .warn("Harmless : Exception while Deleting User Configured Reverse link {} {}",
696 return new Status(StatusCode.SUCCESS, null);
699 private void registerWithOSGIConsole() {
700 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass())
702 bundleContext.registerService(CommandProvider.class.getName(), this,
707 public String getHelp() {
708 StringBuffer help = new StringBuffer();
709 help.append("---Topology Manager---\n");
710 help.append("\t addTopo name <NodeIDType> <src-sw-id> <NodeConnectorIDType> <port-number> <NodeIDType> <dst-sw-id> <NodeConnectorIDType> <port-number>\n");
711 help.append("\t delTopo name\n");
712 help.append("\t printTopo\n");
713 help.append("\t printNodeEdges\n");
714 return help.toString();
717 public void _printTopo(CommandInterpreter ci) {
718 for (String name : this.userLinks.keySet()) {
719 TopologyUserLinkConfig linkConfig = userLinks.get(name);
720 ci.println("Name : " + name);
721 ci.println(linkConfig);
722 ci.println("Edge " + getLinkTuple(linkConfig));
723 ci.println("Reverse Edge " + getReverseLinkTuple(linkConfig));
727 public void _addTopo(CommandInterpreter ci) {
728 String name = ci.nextArgument();
729 if ((name == null)) {
730 ci.println("Please enter a valid Name");
734 String srcNodeIDType = ci.nextArgument();
735 if (srcNodeIDType == null) {
736 ci.println("Null source node ID Type. Example: OF or PR");
740 String dpid = ci.nextArgument();
742 ci.println("Null source node id");
746 String srcNodeConnectorIDType = ci.nextArgument();
747 if (srcNodeConnectorIDType == null) {
748 ci.println("Null source node connector ID Type. Example: OF or PR");
752 String port = ci.nextArgument();
754 ci.println("Null source port number");
758 String dstNodeIDType = ci.nextArgument();
759 if (dstNodeIDType == null) {
760 ci.println("Null destination node ID Type. Example: OF or PR");
764 String ddpid = ci.nextArgument();
766 ci.println("Null destination node ID");
770 String dstNodeConnectorIDType = ci.nextArgument();
771 if (dstNodeConnectorIDType == null) {
772 ci.println("Null destination node connector ID Type. Example: OF or PR");
776 String dport = ci.nextArgument();
778 ci.println("Null destination port number");
781 TopologyUserLinkConfig config = new TopologyUserLinkConfig(name,
782 srcNodeIDType, dpid, srcNodeConnectorIDType, port,
783 dstNodeIDType, ddpid, dstNodeConnectorIDType, dport);
784 ci.println(this.addUserLink(config));
787 public void _delTopo(CommandInterpreter ci) {
788 String name = ci.nextArgument();
789 if ((name == null)) {
790 ci.println("Please enter a valid Name");
793 this.deleteUserLink(name);
796 public void _printNodeEdges(CommandInterpreter ci) {
797 Map<Node, Set<Edge>> nodeEdges = getNodeEdges();
798 if (nodeEdges == null) {
801 Set<Node> nodeSet = nodeEdges.keySet();
802 if (nodeSet == null) {
805 ci.println(" Node Edge");
806 for (Node node : nodeSet) {
807 Set<Edge> edgeSet = nodeEdges.get(node);
808 if (edgeSet == null) {
811 for (Edge edge : edgeSet) {
812 ci.println(node + " " + edge);
818 public Object readObject(ObjectInputStream ois)
819 throws FileNotFoundException, IOException, ClassNotFoundException {
820 // TODO Auto-generated method stub
821 return ois.readObject();
825 public Status saveConfiguration() {
830 public void edgeOverUtilized(Edge edge) {
831 log.warn("Link Utilization above normal: {}", edge);
835 public void edgeUtilBackToNormal(Edge edge) {
836 log.warn("Link Utilization back to normal: {}", edge);