2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.protocol_plugin.openflow.internal;
11 import java.nio.charset.Charset;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.HashSet;
16 import java.util.List;
19 import java.util.Timer;
20 import java.util.TimerTask;
21 import java.util.concurrent.BlockingQueue;
22 import java.util.concurrent.ConcurrentHashMap;
23 import java.util.concurrent.ConcurrentMap;
24 import java.util.concurrent.CopyOnWriteArrayList;
25 import java.util.concurrent.LinkedBlockingQueue;
27 import org.eclipse.osgi.framework.console.CommandInterpreter;
28 import org.eclipse.osgi.framework.console.CommandProvider;
29 import org.opendaylight.controller.protocol_plugin.openflow.IDataPacketListen;
30 import org.opendaylight.controller.protocol_plugin.openflow.IDataPacketMux;
31 import org.opendaylight.controller.protocol_plugin.openflow.IDiscoveryListener;
32 import org.opendaylight.controller.protocol_plugin.openflow.IInventoryProvider;
33 import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener;
34 import org.opendaylight.controller.protocol_plugin.openflow.core.IController;
35 import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch;
36 import org.opendaylight.controller.sal.connection.IPluginOutConnectionService;
37 import org.opendaylight.controller.sal.core.Config;
38 import org.opendaylight.controller.sal.core.ConstructionException;
39 import org.opendaylight.controller.sal.core.ContainerFlow;
40 import org.opendaylight.controller.sal.core.Edge;
41 import org.opendaylight.controller.sal.core.IContainerListener;
42 import org.opendaylight.controller.sal.core.Node;
43 import org.opendaylight.controller.sal.core.NodeConnector;
44 import org.opendaylight.controller.sal.core.Property;
45 import org.opendaylight.controller.sal.core.State;
46 import org.opendaylight.controller.sal.core.UpdateType;
47 import org.opendaylight.controller.sal.packet.Ethernet;
48 import org.opendaylight.controller.sal.packet.LLDP;
49 import org.opendaylight.controller.sal.packet.LLDPTLV;
50 import org.opendaylight.controller.sal.packet.LinkEncap;
51 import org.opendaylight.controller.sal.packet.PacketResult;
52 import org.opendaylight.controller.sal.packet.RawPacket;
53 import org.opendaylight.controller.sal.utils.EtherTypes;
54 import org.opendaylight.controller.sal.utils.HexEncode;
55 import org.opendaylight.controller.sal.utils.NetUtils;
56 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
57 import org.opendaylight.controller.sal.utils.NodeCreator;
58 import org.openflow.protocol.OFPhysicalPort;
59 import org.osgi.framework.BundleContext;
60 import org.osgi.framework.FrameworkUtil;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
65 * The class describes neighbor discovery service for an OpenFlow network.
67 public class DiscoveryService implements IInventoryShimExternalListener, IDataPacketListen, IContainerListener,
69 private static Logger logger = LoggerFactory.getLogger(DiscoveryService.class);
70 private IController controller = null;
71 private IDiscoveryListener discoveryListener = null;
72 private IInventoryProvider inventoryProvider = null;
73 private IDataPacketMux iDataPacketMux = null;
74 // High priority list containing newly added ports which will be served first
75 private List<NodeConnector> readyListHi = null;
76 // List containing all the ports which will be served periodically
77 private List<NodeConnector> readyListLo = null;
78 // Staging area during quiet period
79 private List<NodeConnector> stagingList = null;
80 // Wait for next discovery packet. The map contains the time elapsed since
81 // the last received LLDP frame on each node connector
82 private ConcurrentMap<NodeConnector, Integer> holdTime = null;
83 // Allow one more retry for newly added ports. This map contains the time
84 // period elapsed since last discovery pkt transmission on the port.
85 private ConcurrentMap<NodeConnector, Integer> elapsedTime = null;
86 // OpenFlow edges keyed by head connector
87 private ConcurrentMap<NodeConnector, Edge> edgeMap = null;
88 // The map contains aging entry keyed by head connector of Production edge
89 private ConcurrentMap<NodeConnector, Integer> agingMap = null;
90 // Production edges keyed by head connector
91 private ConcurrentMap<NodeConnector, Edge> prodMap = null;
93 private Timer discoveryTimer;
94 private DiscoveryTimerTask discoveryTimerTask;
95 private final static long discoveryTimerTick = 2L * 1000; // per tick in msec
96 private int discoveryTimerTickCount = 0; // main tick counter
97 // Max # of ports handled in one batch
98 private int discoveryBatchMaxPorts;
99 // Periodically restart batching process
100 private int discoveryBatchRestartTicks;
101 private int discoveryBatchPausePeriod = 2;
102 // Pause after this point
103 private int discoveryBatchPauseTicks;
104 private int discoveryTimeoutTicks;
105 private int discoveryThresholdTicks;
106 private int discoveryAgeoutTicks;
107 // multiple of discoveryBatchRestartTicks
108 private int discoveryConsistencyCheckMultiple = 2;
110 private int discoveryConsistencyCheckTickCount;
111 // # of times CC gets called
112 private int discoveryConsistencyCheckCallingTimes = 0;
113 // # of cases CC corrected
114 private int discoveryConsistencyCheckCorrected = 0;
115 // Enable or disable CC
116 private boolean discoveryConsistencyCheckEnabled = true;
117 // Enable or disable aging
118 private boolean discoveryAgingEnabled = true;
119 // Global flag to enable or disable LLDP snooping
120 private boolean discoverySnoopingEnabled = true;
121 // The list of ports that will not do LLDP snooping
122 private List<NodeConnector> discoverySnoopingDisableList;
123 private BlockingQueue<NodeConnector> transmitQ;
124 private Thread transmitThread;
125 private Boolean throttling = false; // if true, no more batching.
126 private volatile Boolean shuttingDown = false;
128 private LLDPTLV chassisIdTlv, systemNameTlv, portIdTlv, ttlTlv, customTlv;
129 private IPluginOutConnectionService connectionOutService;
131 class DiscoveryTransmit implements Runnable {
132 private final BlockingQueue<NodeConnector> transmitQ;
133 private int count = 0;
135 DiscoveryTransmit(BlockingQueue<NodeConnector> transmitQ) {
136 this.transmitQ = transmitQ;
143 NodeConnector nodeConnector = transmitQ.take();
144 RawPacket outPkt = createDiscoveryPacket(nodeConnector);
145 sendDiscoveryPacket(nodeConnector, outPkt);
146 nodeConnector = null;
147 if ((++count & 0x7f) == 0) {
150 } catch (InterruptedException e1) {
151 logger.trace("DiscoveryTransmit interupted", e1.getMessage());
155 } catch (Exception e2) {
156 logger.error("", e2);
162 class DiscoveryTimerTask extends TimerTask {
167 doConsistencyCheck();
172 public enum DiscoveryPeriod {
177 private int time; // sec
178 private int tick; // tick
180 DiscoveryPeriod(int time) {
182 this.tick = time2Tick(time);
185 public int getTime() {
189 public void setTime(int time) {
191 this.tick = time2Tick(time);
194 public int getTick() {
198 public void setTick(int tick) {
199 this.time = tick2Time(tick);
203 private int time2Tick(int time) {
204 return (int) (time / (discoveryTimerTick / 1000));
207 private int tick2Time(int tick) {
208 return (int) (tick * (discoveryTimerTick / 1000));
212 private RawPacket createDiscoveryPacket(NodeConnector nodeConnector) {
213 String nodeId = HexEncode.longToHexString((Long) nodeConnector.getNode().getID());
215 // Create LLDP ChassisID TLV
216 byte[] cidValue = LLDPTLV.createChassisIDTLVValue(nodeId);
217 chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue()).setLength((short) cidValue.length)
220 // Create LLDP SystemName TLV
221 byte[] snValue = LLDPTLV.createSystemNameTLVValue(nodeConnector.getNode().toString());
222 systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue()).setLength((short) snValue.length)
225 // Create LLDP PortID TLV
226 String portId = nodeConnector.getNodeConnectorIDString();
227 byte[] pidValue = LLDPTLV.createPortIDTLVValue(portId);
228 portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue()).setLength((short) pidValue.length).setValue(pidValue);
230 // Create LLDP Custom TLV
231 byte[] customValue = LLDPTLV.createCustomTLVValue(nodeConnector.toString());
232 customTlv.setType(LLDPTLV.TLVType.Custom.getValue()).setLength((short) customValue.length)
233 .setValue(customValue);
235 // Create LLDP Custom Option list
236 List<LLDPTLV> customList = new ArrayList<LLDPTLV>();
237 customList.add(customTlv);
239 // Create discovery pkt
240 LLDP discoveryPkt = new LLDP();
241 discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setSystemNameId(systemNameTlv)
242 .setOptionalTLVList(customList);
244 RawPacket rawPkt = null;
246 // Create ethernet pkt
247 byte[] sourceMac = getSourceMACFromNodeID(nodeId);
248 Ethernet ethPkt = new Ethernet();
249 ethPkt.setSourceMACAddress(sourceMac).setDestinationMACAddress(LLDP.LLDPMulticastMac)
250 .setEtherType(EtherTypes.LLDP.shortValue()).setPayload(discoveryPkt);
252 byte[] data = ethPkt.serialize();
253 rawPkt = new RawPacket(data);
254 rawPkt.setOutgoingNodeConnector(nodeConnector);
255 } catch (ConstructionException cex) {
256 logger.warn("RawPacket creation caught exception {}", cex.getMessage());
257 } catch (Exception e) {
258 logger.error("Failed to serialize the LLDP packet: " + e);
264 private void sendDiscoveryPacket(NodeConnector nodeConnector, RawPacket outPkt) {
265 if (nodeConnector == null) {
266 logger.debug("Can not send discovery packet out since nodeConnector is null");
270 if (!connectionOutService.isLocal(nodeConnector.getNode())) {
271 logger.debug("Discoery packets will not be sent to {} in a non-master controller", nodeConnector.toString());
275 if (outPkt == null) {
276 logger.debug("Can not send discovery packet out since outPkt is null");
280 long sid = (Long) nodeConnector.getNode().getID();
281 ISwitch sw = controller.getSwitches().get(sid);
284 logger.debug("Can not send discovery packet out since switch {} is null", sid);
288 if (!sw.isOperational()) {
289 logger.debug("Can not send discovery packet out since switch {} is not operational", sw);
293 if (this.iDataPacketMux == null) {
294 logger.debug("Can not send discovery packet out since DataPacket service is not available");
298 logger.trace("Sending topology discovery pkt thru {}", nodeConnector);
299 this.iDataPacketMux.transmitDataPacket(outPkt);
303 public PacketResult receiveDataPacket(RawPacket inPkt) {
305 logger.debug("Ignoring null packet");
306 return PacketResult.IGNORED;
309 byte[] data = inPkt.getPacketData();
310 if (data.length <= 0) {
311 logger.trace("Ignoring zero length packet");
312 return PacketResult.IGNORED;
315 if (!inPkt.getEncap().equals(LinkEncap.ETHERNET)) {
316 logger.trace("Ignoring non ethernet packet");
317 return PacketResult.IGNORED;
320 NodeConnector nodeConnector = inPkt.getIncomingNodeConnector();
321 if (((Short) nodeConnector.getID()).equals(NodeConnector.SPECIALNODECONNECTORID)) {
322 logger.trace("Ignoring ethernet packet received on special port: "
323 + inPkt.getIncomingNodeConnector().toString());
324 return PacketResult.IGNORED;
327 if (!connectionOutService.isLocal(nodeConnector.getNode())) {
328 logger.debug("Discoery packets will not be processed from {} in a non-master controller", nodeConnector.toString());
329 return PacketResult.IGNORED;
332 Ethernet ethPkt = new Ethernet();
334 ethPkt.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
335 } catch (Exception e) {
336 logger.warn("Failed to decode LLDP packet from {}: {}", inPkt.getIncomingNodeConnector(), e);
337 return PacketResult.IGNORED;
340 if (ethPkt.getPayload() instanceof LLDP) {
341 NodeConnector dst = inPkt.getIncomingNodeConnector();
342 if (isEnabled(dst)) {
343 if (!processDiscoveryPacket(dst, ethPkt)) {
344 // Snoop the discovery pkt if not generated from us
345 snoopDiscoveryPacket(dst, ethPkt);
347 return PacketResult.CONSUME;
350 return PacketResult.IGNORED;
354 * Snoop incoming discovery frames generated by the production network
357 private void snoopDiscoveryPacket(NodeConnector dstNodeConnector, Ethernet ethPkt) {
358 if (!this.discoverySnoopingEnabled || discoverySnoopingDisableList.contains(dstNodeConnector)) {
359 logger.trace("Discarded received discovery packet on {} since snooping is turned off", dstNodeConnector);
363 if ((dstNodeConnector == null) || (ethPkt == null)) {
364 logger.trace("Quit snooping discovery packet: Null node connector or packet");
368 LLDP lldp = (LLDP) ethPkt.getPayload();
371 String nodeId = LLDPTLV.getHexStringValue(lldp.getChassisId().getValue(), lldp.getChassisId().getLength());
372 String portId = LLDPTLV.getStringValue(lldp.getPortId().getValue(), lldp.getPortId().getLength());
373 byte[] systemNameBytes = null;
374 // get system name if present in the LLDP pkt
375 for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) {
376 if (lldptlv.getType() == LLDPTLV.TLVType.SystemName.getValue()) {
377 systemNameBytes = lldptlv.getValue();
381 String nodeName = (systemNameBytes == null) ? nodeId
382 : new String(systemNameBytes, Charset.defaultCharset());
383 Node srcNode = new Node(Node.NodeIDType.PRODUCTION, nodeName);
384 NodeConnector srcNodeConnector = NodeConnectorCreator.createNodeConnector(
385 NodeConnector.NodeConnectorIDType.PRODUCTION, portId, srcNode);
388 Set<Property> props = null;
389 edge = new Edge(srcNodeConnector, dstNodeConnector);
390 props = getProps(dstNodeConnector);
392 updateProdEdge(edge, props);
393 } catch (Exception e) {
394 if (logger.isDebugEnabled()) {
396 "Caught exception while attempting to snoop non controller generated or malformed LLDP frame sent by {} and received on {}: {}",
397 HexEncode.bytesToHexStringFormat(ethPkt.getSourceMACAddress()), dstNodeConnector,
404 * Handle discovery frames generated by our controller
406 * @return true if it's a success
408 private boolean processDiscoveryPacket(NodeConnector dstNodeConnector, Ethernet ethPkt) {
409 if ((dstNodeConnector == null) || (ethPkt == null)) {
410 logger.trace("Ignoring processing of discovery packet: Null node connector or packet");
414 logger.trace("Handle discovery packet {} from {}", ethPkt, dstNodeConnector);
416 LLDP lldp = (LLDP) ethPkt.getPayload();
418 List<LLDPTLV> optionalTLVList = lldp.getOptionalTLVList();
419 if (optionalTLVList == null) {
420 logger.warn("The discovery packet with null custom option from {}", dstNodeConnector);
425 NodeConnector srcNodeConnector = null;
426 for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) {
427 if (lldptlv.getType() == LLDPTLV.TLVType.Custom.getValue()) {
428 String ncString = LLDPTLV.getCustomString(lldptlv.getValue(), lldptlv.getLength());
429 srcNodeConnector = NodeConnector.fromString(ncString);
430 if (srcNodeConnector != null) {
431 srcNode = srcNodeConnector.getNode();
436 if ((srcNode == null) || (srcNodeConnector == null)) {
437 logger.trace("Received non-controller generated discovery packet from {}", dstNodeConnector);
441 // push it out to Topology
443 Set<Property> props = null;
445 edge = new Edge(srcNodeConnector, dstNodeConnector);
446 props = getProps(dstNodeConnector);
447 } catch (ConstructionException e) {
448 logger.error("Caught exception ", e);
450 addEdge(edge, props);
452 logger.trace("Received discovery packet for Edge {}", edge);
457 public Map<String, Property> getPropMap(NodeConnector nodeConnector) {
458 if (nodeConnector == null) {
462 if (inventoryProvider == null) {
466 Map<NodeConnector, Map<String, Property>> props = inventoryProvider.getNodeConnectorProps(false);
471 return props.get(nodeConnector);
474 public Property getProp(NodeConnector nodeConnector, String propName) {
475 Map<String, Property> propMap = getPropMap(nodeConnector);
476 if (propMap == null) {
480 Property prop = propMap.get(propName);
484 public Set<Property> getProps(NodeConnector nodeConnector) {
485 Map<String, Property> propMap = getPropMap(nodeConnector);
486 if (propMap == null) {
490 Set<Property> props = new HashSet<Property>(propMap.values());
494 private boolean isEnabled(NodeConnector nodeConnector) {
495 if (nodeConnector == null) {
499 Config config = (Config) getProp(nodeConnector, Config.ConfigPropName);
500 State state = (State) getProp(nodeConnector, State.StatePropName);
501 return ((config != null) && (config.getValue() == Config.ADMIN_UP) && (state != null) && (state.getValue() == State.EDGE_UP));
504 private boolean isTracked(NodeConnector nodeConnector) {
505 if (readyListHi.contains(nodeConnector)) {
509 if (readyListLo.contains(nodeConnector)) {
513 if (holdTime.keySet().contains(nodeConnector)) {
517 if (stagingList.contains(nodeConnector)) {
524 private Set<NodeConnector> getWorkingSet() {
525 Set<NodeConnector> workingSet = new HashSet<NodeConnector>();
526 Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
528 for (NodeConnector nodeConnector : readyListHi) {
529 if (isOverLimit(workingSet.size())) {
533 workingSet.add(nodeConnector);
534 removeSet.add(nodeConnector);
536 // Put it in the map and start the timer. It may need retry.
537 elapsedTime.put(nodeConnector, 0);
539 readyListHi.removeAll(removeSet);
542 for (NodeConnector nodeConnector : readyListLo) {
543 if (isOverLimit(workingSet.size())) {
547 workingSet.add(nodeConnector);
548 removeSet.add(nodeConnector);
550 readyListLo.removeAll(removeSet);
555 private Boolean isOverLimit(int size) {
556 return ((size >= discoveryBatchMaxPorts) && !throttling);
559 private void addDiscovery() {
560 Map<Long, ISwitch> switches = controller.getSwitches();
561 Set<Long> sidSet = switches.keySet();
562 if (sidSet == null) {
565 for (Long sid : sidSet) {
566 Node node = NodeCreator.createOFNode(sid);
571 private void addDiscovery(Node node) {
572 Map<Long, ISwitch> switches = controller.getSwitches();
573 ISwitch sw = switches.get(node.getID());
575 //switch could be removed by now, stop propagation
578 List<OFPhysicalPort> ports = sw.getEnabledPorts();
579 for (OFPhysicalPort port : ports) {
580 NodeConnector nodeConnector = NodeConnectorCreator.createOFNodeConnector(port.getPortNumber(), node);
581 if (!readyListHi.contains(nodeConnector)) {
582 readyListHi.add(nodeConnector);
587 private void addDiscovery(NodeConnector nodeConnector) {
588 if (isTracked(nodeConnector)) {
592 readyListHi.add(nodeConnector);
595 private void removeNodeConnector(NodeConnector nodeConnector) {
596 readyListLo.remove(nodeConnector);
597 readyListHi.remove(nodeConnector);
598 stagingList.remove(nodeConnector);
599 holdTime.remove(nodeConnector);
600 elapsedTime.remove(nodeConnector);
603 private Set<NodeConnector> getRemoveSet(Collection<NodeConnector> c, Node node) {
604 Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
608 for (NodeConnector nodeConnector : c) {
609 if (node.equals(nodeConnector.getNode())) {
610 removeSet.add(nodeConnector);
616 private void removeDiscovery(Node node) {
617 Set<NodeConnector> removeSet;
619 removeSet = getRemoveSet(edgeMap.keySet(), node);
620 NodeConnector peerConnector;
622 for (NodeConnector nodeConnector : removeSet) {
623 // get the peer for fast removal of the edge in reverse direction
624 peerConnector = null;
625 edge1 = edgeMap.get(nodeConnector);
627 edge2 = edgeMap.get(edge1.getTailNodeConnector());
628 if ((edge2 != null) && node.equals(edge2.getTailNodeConnector().getNode())) {
629 peerConnector = edge2.getHeadNodeConnector();
633 removeEdge(nodeConnector, false);
634 removeEdge(peerConnector, isEnabled(peerConnector));
637 removeSet = getRemoveSet(prodMap.keySet(), node);
638 for (NodeConnector nodeConnector : removeSet) {
639 removeProdEdge(nodeConnector);
642 removeSet = getRemoveSet(readyListHi, node);
643 readyListHi.removeAll(removeSet);
645 removeSet = getRemoveSet(readyListLo, node);
646 readyListLo.removeAll(removeSet);
648 removeSet = getRemoveSet(stagingList, node);
649 stagingList.removeAll(removeSet);
651 removeSet = getRemoveSet(holdTime.keySet(), node);
652 for (NodeConnector nodeConnector : removeSet) {
653 holdTime.remove(nodeConnector);
656 removeSet = getRemoveSet(elapsedTime.keySet(), node);
657 for (NodeConnector nodeConnector : removeSet) {
658 elapsedTime.remove(nodeConnector);
662 private void removeDiscovery(NodeConnector nodeConnector) {
663 removeNodeConnector(nodeConnector);
664 removeEdge(nodeConnector, false);
665 removeProdEdge(nodeConnector);
668 private void checkTimeout() {
669 Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
672 Set<NodeConnector> monitorSet = holdTime.keySet();
673 if (monitorSet != null) {
674 for (NodeConnector nodeConnector : monitorSet) {
675 ticks = holdTime.get(nodeConnector);
676 holdTime.put(nodeConnector, ++ticks);
677 if (ticks >= discoveryTimeoutTicks) {
679 removeSet.add(nodeConnector);
680 logger.trace("Discovery timeout {}", nodeConnector);
685 for (NodeConnector nodeConnector : removeSet) {
686 removeEdge(nodeConnector);
689 Set<NodeConnector> retrySet = new HashSet<NodeConnector>();
690 Set<NodeConnector> ncSet = elapsedTime.keySet();
691 if ((ncSet != null) && (ncSet.size() > 0)) {
692 for (NodeConnector nodeConnector : ncSet) {
693 ticks = elapsedTime.get(nodeConnector);
694 elapsedTime.put(nodeConnector, ++ticks);
695 if (ticks >= discoveryThresholdTicks) {
696 retrySet.add(nodeConnector);
700 for (NodeConnector nodeConnector : retrySet) {
701 // Allow one more retry
702 elapsedTime.remove(nodeConnector);
703 if (connectionOutService.isLocal(nodeConnector.getNode())) {
704 transmitQ.add(nodeConnector);
710 private void checkAging() {
711 if (!discoveryAgingEnabled) {
715 Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
718 Set<NodeConnector> agingSet = agingMap.keySet();
719 if (agingSet != null) {
720 for (NodeConnector nodeConnector : agingSet) {
721 ticks = agingMap.get(nodeConnector);
722 agingMap.put(nodeConnector, ++ticks);
723 if (ticks > discoveryAgeoutTicks) {
725 removeSet.add(nodeConnector);
726 logger.trace("Discovery age out {}", nodeConnector);
731 for (NodeConnector nodeConnector : removeSet) {
732 removeProdEdge(nodeConnector);
736 private void doDiscovery() {
737 if (++discoveryTimerTickCount <= discoveryBatchPauseTicks) {
738 for (NodeConnector nodeConnector : getWorkingSet()) {
739 if (connectionOutService.isLocal(nodeConnector.getNode())) {
740 transmitQ.add(nodeConnector);
741 // Move to staging area after it's served
742 if (!stagingList.contains(nodeConnector)) {
743 stagingList.add(nodeConnector);
747 } else if (discoveryTimerTickCount >= discoveryBatchRestartTicks) {
748 discoveryTimerTickCount = 0;
749 for (NodeConnector nodeConnector : stagingList) {
750 if (!readyListLo.contains(nodeConnector)) {
751 readyListLo.add(nodeConnector);
754 stagingList.removeAll(readyListLo);
758 private void doConsistencyCheck() {
759 if (!discoveryConsistencyCheckEnabled) {
763 if (++discoveryConsistencyCheckTickCount % getDiscoveryConsistencyCheckInterval() != 0) {
767 discoveryConsistencyCheckCallingTimes++;
769 Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
770 Set<NodeConnector> ncSet = edgeMap.keySet();
774 for (NodeConnector nodeConnector : ncSet) {
775 if (!isEnabled(nodeConnector)) {
776 removeSet.add(nodeConnector);
777 discoveryConsistencyCheckCorrected++;
778 logger.debug("ConsistencyChecker: remove disabled {}", nodeConnector);
782 if (!isTracked(nodeConnector)) {
783 stagingList.add(nodeConnector);
784 discoveryConsistencyCheckCorrected++;
785 logger.debug("ConsistencyChecker: add back untracked {}", nodeConnector);
790 for (NodeConnector nodeConnector : removeSet) {
791 removeEdge(nodeConnector, false);
794 // remove stale entries
796 for (NodeConnector nodeConnector : stagingList) {
797 if (!isEnabled(nodeConnector)) {
798 removeSet.add(nodeConnector);
799 discoveryConsistencyCheckCorrected++;
800 logger.debug("ConsistencyChecker: remove disabled {}", nodeConnector);
803 stagingList.removeAll(removeSet);
805 // Get a snapshot of all the existing switches
806 Map<Long, ISwitch> switches = this.controller.getSwitches();
807 for (ISwitch sw : switches.values()) {
808 for (OFPhysicalPort port : sw.getEnabledPorts()) {
809 Node node = NodeCreator.createOFNode(sw.getId());
810 NodeConnector nodeConnector = NodeConnectorCreator.createOFNodeConnector(port.getPortNumber(), node);
811 if (!isTracked(nodeConnector)) {
812 stagingList.add(nodeConnector);
813 discoveryConsistencyCheckCorrected++;
814 logger.debug("ConsistencyChecker: add back untracked {}", nodeConnector);
820 private void addEdge(Edge edge, Set<Property> props) {
825 NodeConnector src = edge.getTailNodeConnector();
826 NodeConnector dst = edge.getHeadNodeConnector();
827 if (!src.getType().equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) {
828 holdTime.put(dst, 0);
830 agingMap.put(dst, 0);
832 elapsedTime.remove(src);
834 // fast discovery of the edge in reverse direction
835 if (!edgeMap.containsKey(dst) && !readyListHi.contains(dst) && !elapsedTime.keySet().contains(dst)) {
836 moveToReadyListHi(dst);
839 //checking only OF map, since production edge discovery always overwrites any existing edge
840 UpdateType ut = edgeMap.containsKey(dst) ? UpdateType.CHANGED : UpdateType.ADDED;
842 updateEdge(edge, ut, props);
843 logger.trace("Add edge {}", edge);
847 * Update Production Edge
850 * The Production Edge
852 * Properties associated with the edge
854 private void updateProdEdge(Edge edge, Set<Property> props) {
855 NodeConnector edgePort = edge.getHeadNodeConnector();
857 /* Do not update in case there is an existing OpenFlow link */
858 if (edgeMap.get(edgePort) != null) {
859 logger.trace("Discarded edge {} since there is an existing OF link {}", edge, edgeMap.get(edgePort));
863 /* Look for any existing Production Edge */
864 Edge oldEdge = prodMap.get(edgePort);
865 if (oldEdge == null) {
866 /* Let's add a new one */
867 addEdge(edge, props);
868 } else if (!edge.equals(oldEdge)) {
869 /* Remove the old one first */
870 removeProdEdge(oldEdge.getHeadNodeConnector());
871 /* Then add the new one */
872 addEdge(edge, props);
874 /* o/w, just reset the aging timer */
875 NodeConnector dst = edge.getHeadNodeConnector();
876 agingMap.put(dst, 0);
881 * Remove Production Edge for a given edge port
886 private void removeProdEdge(NodeConnector edgePort) {
887 agingMap.remove(edgePort);
890 Set<NodeConnector> prodKeySet = prodMap.keySet();
891 if ((prodKeySet != null) && (prodKeySet.contains(edgePort))) {
892 edge = prodMap.get(edgePort);
893 prodMap.remove(edgePort);
897 if (this.discoveryListener != null) {
898 this.discoveryListener.notifyEdge(edge, UpdateType.REMOVED, null);
900 logger.trace("Remove edge {}", edge);
904 * Remove OpenFlow edge
906 private void removeEdge(NodeConnector nodeConnector, boolean stillEnabled) {
907 if (nodeConnector == null) {
911 removeNodeConnector(nodeConnector);
915 stagingList.add(nodeConnector);
919 Set<NodeConnector> edgeKeySet = edgeMap.keySet();
920 if ((edgeKeySet != null) && (edgeKeySet.contains(nodeConnector))) {
921 edge = edgeMap.get(nodeConnector);
922 edgeMap.remove(nodeConnector);
926 if (this.discoveryListener != null) {
927 this.discoveryListener.notifyEdge(edge, UpdateType.REMOVED, null);
929 logger.trace("Remove {}", nodeConnector);
932 private void removeEdge(NodeConnector nodeConnector) {
933 removeEdge(nodeConnector, isEnabled(nodeConnector));
936 private void updateEdge(Edge edge, UpdateType type, Set<Property> props) {
937 if (discoveryListener == null) {
942 this.discoveryListener.notifyEdge(edge, type, props);
944 NodeConnector src = edge.getTailNodeConnector(), dst = edge.getHeadNodeConnector();
945 if (!src.getType().equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) {
946 if (type == UpdateType.ADDED) {
947 edgeMap.put(dst, edge);
948 } else if (type == UpdateType.REMOVED) {
953 * Save Production edge into different DB keyed by the Edge port
955 if (type == UpdateType.ADDED) {
956 prodMap.put(dst, edge);
957 } else if (type == UpdateType.REMOVED) {
963 private void moveToReadyListHi(NodeConnector nodeConnector) {
964 if (readyListLo.contains(nodeConnector)) {
965 readyListLo.remove(nodeConnector);
966 } else if (stagingList.contains(nodeConnector)) {
967 stagingList.remove(nodeConnector);
969 readyListHi.add(nodeConnector);
972 private void registerWithOSGIConsole() {
973 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
974 bundleContext.registerService(CommandProvider.class.getName(), this, null);
977 private int getDiscoveryConsistencyCheckInterval() {
978 return discoveryConsistencyCheckMultiple * discoveryBatchRestartTicks;
982 public String getHelp() {
983 StringBuffer help = new StringBuffer();
984 help.append("---Topology Discovery---\n");
985 help.append("\t prlh - Print readyListHi entries\n");
986 help.append("\t prll - Print readyListLo entries\n");
987 help.append("\t psl - Print stagingList entries\n");
988 help.append("\t pht - Print hold time\n");
989 help.append("\t pet - Print elapsed time\n");
990 help.append("\t ptick - Print tick time in msec\n");
991 help.append("\t pcc - Print CC info\n");
992 help.append("\t psize - Print sizes of all the lists\n");
993 help.append("\t ptm - Print timeout info\n");
994 help.append("\t ecc - Enable CC\n");
995 help.append("\t dcc - Disable CC\n");
996 help.append("\t scc [multiple] - Set/show CC multiple and interval\n");
997 help.append("\t sports [ports] - Set/show max ports per batch\n");
998 help.append("\t spause [ticks] - Set/show pause period\n");
999 help.append("\t sdi [ticks] - Set/show discovery interval in ticks\n");
1000 help.append("\t addsw <swid> - Add a switch\n");
1001 help.append("\t remsw <swid> - Remove a switch\n");
1002 help.append("\t page - Print aging info\n");
1003 help.append("\t sage - Set/Show aging time limit\n");
1004 help.append("\t eage - Enable aging\n");
1005 help.append("\t dage - Disable aging\n");
1006 help.append("\t pthrot - Print throttling\n");
1007 help.append("\t ethrot - Enable throttling\n");
1008 help.append("\t dthrot - Disable throttling\n");
1009 help.append("\t psnp - Print LLDP snooping\n");
1010 help.append("\t esnp <all|nodeConnector> - Enable LLDP snooping\n");
1011 help.append("\t dsnp <all|nodeConnector> - Disable LLDP snooping\n");
1012 return help.toString();
1015 private List<NodeConnector> sortList(Collection<NodeConnector> ncs) {
1016 List<String> ncStrArray = new ArrayList<String>();
1017 for (NodeConnector nc : ncs) {
1018 ncStrArray.add(nc.toString());
1020 Collections.sort(ncStrArray);
1022 List<NodeConnector> sortedNodeConnectors = new ArrayList<NodeConnector>();
1023 for (String ncStr : ncStrArray) {
1024 sortedNodeConnectors.add(NodeConnector.fromString(ncStr));
1027 return sortedNodeConnectors;
1030 public void _prlh(CommandInterpreter ci) {
1031 ci.println("readyListHi\n");
1032 for (NodeConnector nodeConnector : sortList(readyListHi)) {
1033 if (nodeConnector == null) {
1036 ci.println(nodeConnector);
1038 ci.println("Total number of Node Connectors: " + readyListHi.size());
1041 public void _prll(CommandInterpreter ci) {
1042 ci.println("readyListLo\n");
1043 for (NodeConnector nodeConnector : sortList(readyListLo)) {
1044 if (nodeConnector == null) {
1047 ci.println(nodeConnector);
1049 ci.println("Total number of Node Connectors: " + readyListLo.size());
1052 public void _psl(CommandInterpreter ci) {
1053 ci.println("stagingList\n");
1054 for (NodeConnector nodeConnector : sortList(stagingList)) {
1055 if (nodeConnector == null) {
1058 ci.println(nodeConnector);
1060 ci.println("Total number of Node Connectors: " + stagingList.size());
1063 public void _pht(CommandInterpreter ci) {
1064 ci.println(" NodeConnector Last rx LLDP (sec)");
1065 for (ConcurrentMap.Entry<NodeConnector, Integer> entry: holdTime.entrySet()) {
1066 ci.println(entry.getKey() + "\t\t" + entry.getValue() * (discoveryTimerTick / 1000));
1068 ci.println("\nSize: " + holdTime.size() + "\tTimeout: " + discoveryTimeoutTicks * (discoveryTimerTick / 1000)
1072 public void _pet(CommandInterpreter ci) {
1073 ci.println(" NodeConnector Elapsed Time (sec)");
1074 for (ConcurrentMap.Entry<NodeConnector, Integer> entry: elapsedTime.entrySet()) {
1075 ci.println(entry.getKey() + "\t\t" + entry.getValue() * (discoveryTimerTick / 1000));
1077 ci.println("\nSize: " + elapsedTime.size() + "\tThreshold: " + DiscoveryPeriod.THRESHOLD.getTime() + " sec");
1080 public void _ptick(CommandInterpreter ci) {
1081 ci.println("Current timer is " + discoveryTimerTick + " msec per tick");
1084 public void _pcc(CommandInterpreter ci) {
1085 if (discoveryConsistencyCheckEnabled) {
1086 ci.println("ConsistencyChecker is currently enabled");
1088 ci.println("ConsistencyChecker is currently disabled");
1090 ci.println("Interval " + getDiscoveryConsistencyCheckInterval());
1091 ci.println("Multiple " + discoveryConsistencyCheckMultiple);
1092 ci.println("Number of times called " + discoveryConsistencyCheckCallingTimes);
1093 ci.println("Corrected count " + discoveryConsistencyCheckCorrected);
1096 public void _ptm(CommandInterpreter ci) {
1097 ci.println("Timeout " + discoveryTimeoutTicks + " ticks, " + discoveryTimerTick / 1000 + " sec per tick.");
1100 public void _psize(CommandInterpreter ci) {
1101 ci.println("readyListLo size " + readyListLo.size() + "\n" + "readyListHi size " + readyListHi.size() + "\n"
1102 + "stagingList size " + stagingList.size() + "\n" + "holdTime size " + holdTime.size() + "\n"
1103 + "edgeMap size " + edgeMap.size() + "\n" + "prodMap size " + prodMap.size() + "\n" + "agingMap size "
1104 + agingMap.size() + "\n" + "elapsedTime size " + elapsedTime.size());
1107 public void _page(CommandInterpreter ci) {
1108 if (this.discoveryAgingEnabled) {
1109 ci.println("Aging is enabled");
1111 ci.println("Aging is disabled");
1113 ci.println("Current aging time limit " + this.discoveryAgeoutTicks);
1115 ci.println(" Edge Aging ");
1116 Collection<Edge> prodSet = prodMap.values();
1117 if (prodSet == null) {
1120 for (Edge edge : prodSet) {
1121 Integer aging = agingMap.get(edge.getHeadNodeConnector());
1122 if (aging != null) {
1123 ci.println(edge + " " + aging);
1127 ci.println(" NodeConnector Edge ");
1128 Set<NodeConnector> keySet = prodMap.keySet();
1129 if (keySet == null) {
1132 for (NodeConnector nc : keySet) {
1133 ci.println(nc + " " + prodMap.get(nc));
1138 public void _sage(CommandInterpreter ci) {
1139 String val = ci.nextArgument();
1141 ci.println("Please enter aging time limit. Current value " + this.discoveryAgeoutTicks);
1145 this.discoveryAgeoutTicks = Integer.parseInt(val);
1146 } catch (Exception e) {
1147 ci.println("Please enter a valid number");
1152 public void _eage(CommandInterpreter ci) {
1153 this.discoveryAgingEnabled = true;
1154 ci.println("Aging is enabled");
1158 public void _dage(CommandInterpreter ci) {
1159 this.discoveryAgingEnabled = false;
1160 ci.println("Aging is disabled");
1164 public void _scc(CommandInterpreter ci) {
1165 String val = ci.nextArgument();
1167 ci.println("Please enter CC multiple. Current multiple " + discoveryConsistencyCheckMultiple
1168 + " (interval " + getDiscoveryConsistencyCheckInterval() + ") calling times "
1169 + discoveryConsistencyCheckCallingTimes);
1173 discoveryConsistencyCheckMultiple = Integer.parseInt(val);
1174 } catch (Exception e) {
1175 ci.println("Please enter a valid number");
1180 public void _ecc(CommandInterpreter ci) {
1181 this.discoveryConsistencyCheckEnabled = true;
1182 ci.println("ConsistencyChecker is enabled");
1186 public void _dcc(CommandInterpreter ci) {
1187 this.discoveryConsistencyCheckEnabled = false;
1188 ci.println("ConsistencyChecker is disabled");
1192 public void _psnp(CommandInterpreter ci) {
1193 if (this.discoverySnoopingEnabled) {
1194 ci.println("Discovery snooping is globally enabled");
1196 ci.println("Discovery snooping is globally disabled");
1199 ci.println("\nDiscovery snooping is locally disabled on these ports");
1200 for (NodeConnector nodeConnector : discoverySnoopingDisableList) {
1201 ci.println(nodeConnector);
1206 public void _esnp(CommandInterpreter ci) {
1207 String val = ci.nextArgument();
1210 ci.println("Usage: esnp <all|nodeConnector>");
1211 } else if (val.equalsIgnoreCase("all")) {
1212 this.discoverySnoopingEnabled = true;
1213 ci.println("Discovery snooping is globally enabled");
1215 NodeConnector nodeConnector = NodeConnector.fromString(val);
1216 if (nodeConnector != null) {
1217 discoverySnoopingDisableList.remove(nodeConnector);
1218 ci.println("Discovery snooping is locally enabled on port " + nodeConnector);
1220 ci.println("Entered invalid NodeConnector " + val);
1226 public void _dsnp(CommandInterpreter ci) {
1227 String val = ci.nextArgument();
1230 ci.println("Usage: dsnp <all|nodeConnector>");
1231 } else if (val.equalsIgnoreCase("all")) {
1232 this.discoverySnoopingEnabled = false;
1233 ci.println("Discovery snooping is globally disabled");
1235 NodeConnector nodeConnector = NodeConnector.fromString(val);
1236 if (nodeConnector != null) {
1237 discoverySnoopingDisableList.add(nodeConnector);
1238 ci.println("Discovery snooping is locally disabled on port " + nodeConnector);
1240 ci.println("Entered invalid NodeConnector " + val);
1246 public void _spause(CommandInterpreter ci) {
1247 String val = ci.nextArgument();
1248 String out = "Please enter pause period less than " + discoveryBatchRestartTicks + ". Current pause period is "
1249 + discoveryBatchPausePeriod + " ticks, pause at " + discoveryBatchPauseTicks + " ticks, "
1250 + discoveryTimerTick / 1000 + " sec per tick.";
1254 int pause = Integer.parseInt(val);
1255 if (pause < discoveryBatchRestartTicks) {
1256 discoveryBatchPausePeriod = pause;
1257 discoveryBatchPauseTicks = getDiscoveryPauseInterval();
1260 } catch (Exception e) {
1267 public void _sdi(CommandInterpreter ci) {
1268 String val = ci.nextArgument();
1269 String out = "Please enter discovery interval in ticks. Current value is " + discoveryBatchRestartTicks + " ticks, "
1270 + discoveryTimerTick / 1000 + " sec per tick.";
1275 Set<NodeConnector> monitorSet = holdTime.keySet();
1276 if (monitorSet != null) {
1277 for (NodeConnector nodeConnector : monitorSet) {
1278 holdTime.put(nodeConnector, 0);
1282 ticks = Integer.parseInt(val);
1283 DiscoveryPeriod.INTERVAL.setTick(ticks);
1284 discoveryBatchRestartTicks = getDiscoveryInterval();
1285 discoveryBatchPauseTicks = getDiscoveryPauseInterval();
1286 discoveryTimeoutTicks = getDiscoveryTimeout();
1288 } catch (Exception e) {
1294 public void _sports(CommandInterpreter ci) {
1295 String val = ci.nextArgument();
1297 ci.println("Please enter max ports per batch. Current value is " + discoveryBatchMaxPorts);
1301 discoveryBatchMaxPorts = Integer.parseInt(val);
1302 } catch (Exception e) {
1303 ci.println("Please enter a valid number");
1308 public void _addsw(CommandInterpreter ci) {
1309 String val = ci.nextArgument();
1312 sid = Long.parseLong(val);
1313 Node node = NodeCreator.createOFNode(sid);
1315 } catch (Exception e) {
1316 ci.println("Please enter a valid number");
1321 public void _remsw(CommandInterpreter ci) {
1322 String val = ci.nextArgument();
1325 sid = Long.parseLong(val);
1326 Node node = NodeCreator.createOFNode(sid);
1327 removeDiscovery(node);
1328 } catch (Exception e) {
1329 ci.println("Please enter a valid number");
1334 public void _pthrot(CommandInterpreter ci) {
1335 if (this.throttling) {
1336 ci.println("Throttling is enabled");
1338 ci.println("Throttling is disabled");
1342 public void _ethrot(CommandInterpreter ci) {
1343 this.throttling = true;
1344 ci.println("Throttling is enabled");
1348 public void _dthrot(CommandInterpreter ci) {
1349 this.throttling = false;
1350 ci.println("Throttling is disabled");
1355 public void updateNode(Node node, UpdateType type, Set<Property> props) {
1358 addNode(node, props);
1369 public void updateNodeConnector(NodeConnector nodeConnector, UpdateType type, Set<Property> props) {
1370 Config config = null;
1372 boolean enabled = false;
1374 for (Property prop : props) {
1375 if (prop.getName().equals(Config.ConfigPropName)) {
1376 config = (Config) prop;
1377 } else if (prop.getName().equals(State.StatePropName)) {
1378 state = (State) prop;
1381 enabled = ((config != null) && (config.getValue() == Config.ADMIN_UP) && (state != null) && (state.getValue() == State.EDGE_UP));
1386 addDiscovery(nodeConnector);
1387 logger.trace("ADDED enabled {}", nodeConnector);
1389 logger.trace("ADDED disabled {}", nodeConnector);
1394 addDiscovery(nodeConnector);
1395 logger.trace("CHANGED enabled {}", nodeConnector);
1397 removeDiscovery(nodeConnector);
1398 logger.trace("CHANGED disabled {}", nodeConnector);
1402 removeDiscovery(nodeConnector);
1403 logger.trace("REMOVED enabled {}", nodeConnector);
1410 public void addNode(Node node, Set<Property> props) {
1418 public void removeNode(Node node) {
1423 removeDiscovery(node);
1426 void setController(IController s) {
1427 this.controller = s;
1430 void unsetController(IController s) {
1431 if (this.controller == s) {
1432 this.controller = null;
1436 public void setInventoryProvider(IInventoryProvider service) {
1437 this.inventoryProvider = service;
1440 public void unsetInventoryProvider(IInventoryProvider service) {
1441 this.inventoryProvider = null;
1444 public void setIDataPacketMux(IDataPacketMux service) {
1445 this.iDataPacketMux = service;
1448 public void unsetIDataPacketMux(IDataPacketMux service) {
1449 if (this.iDataPacketMux == service) {
1450 this.iDataPacketMux = null;
1454 void setDiscoveryListener(IDiscoveryListener s) {
1455 this.discoveryListener = s;
1458 void unsetDiscoveryListener(IDiscoveryListener s) {
1459 if (this.discoveryListener == s) {
1460 this.discoveryListener = null;
1464 void setIPluginOutConnectionService(IPluginOutConnectionService s) {
1465 connectionOutService = s;
1468 void unsetIPluginOutConnectionService(IPluginOutConnectionService s) {
1469 if (connectionOutService == s) {
1470 connectionOutService = null;
1474 private void initDiscoveryPacket() {
1475 // Create LLDP ChassisID TLV
1476 chassisIdTlv = new LLDPTLV();
1477 chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue());
1479 // Create LLDP SystemName TLV
1480 systemNameTlv = new LLDPTLV();
1481 systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue());
1483 // Create LLDP PortID TLV
1484 portIdTlv = new LLDPTLV();
1485 portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue());
1487 // Create LLDP TTL TLV
1488 byte[] ttl = new byte[] { (byte) 0, (byte) 120 };
1489 ttlTlv = new LLDPTLV();
1490 ttlTlv.setType(LLDPTLV.TLVType.TTL.getValue()).setLength((short) ttl.length).setValue(ttl);
1492 customTlv = new LLDPTLV();
1496 * Function called by the dependency manager when all the required
1497 * dependencies are satisfied
1501 logger.trace("Init called");
1503 transmitQ = new LinkedBlockingQueue<NodeConnector>();
1505 readyListHi = new CopyOnWriteArrayList<NodeConnector>();
1506 readyListLo = new CopyOnWriteArrayList<NodeConnector>();
1507 stagingList = new CopyOnWriteArrayList<NodeConnector>();
1508 holdTime = new ConcurrentHashMap<NodeConnector, Integer>();
1509 elapsedTime = new ConcurrentHashMap<NodeConnector, Integer>();
1510 edgeMap = new ConcurrentHashMap<NodeConnector, Edge>();
1511 agingMap = new ConcurrentHashMap<NodeConnector, Integer>();
1512 prodMap = new ConcurrentHashMap<NodeConnector, Edge>();
1513 discoverySnoopingDisableList = new CopyOnWriteArrayList<NodeConnector>();
1515 discoveryBatchRestartTicks = getDiscoveryInterval();
1516 discoveryBatchPauseTicks = getDiscoveryPauseInterval();
1517 discoveryTimeoutTicks = getDiscoveryTimeout();
1518 discoveryThresholdTicks = getDiscoveryThreshold();
1519 discoveryAgeoutTicks = getDiscoveryAgeout();
1520 discoveryConsistencyCheckTickCount = discoveryBatchPauseTicks;
1521 discoveryBatchMaxPorts = getDiscoveryBatchMaxPorts();
1523 discoveryTimer = new Timer("DiscoveryService");
1524 discoveryTimerTask = new DiscoveryTimerTask();
1526 transmitThread = new Thread(new DiscoveryTransmit(transmitQ));
1528 initDiscoveryPacket();
1530 registerWithOSGIConsole();
1534 * Function called by the dependency manager when at least one dependency
1535 * become unsatisfied or when the component is shutting down because for
1536 * example bundle is being stopped.
1548 discoveryTimer = null;
1549 discoveryTimerTask = null;
1550 transmitThread = null;
1554 * Function called by dependency manager after "init ()" is called and after
1555 * the services provided by the class are registered in the service registry
1559 discoveryTimer.schedule(discoveryTimerTask, discoveryTimerTick, discoveryTimerTick);
1560 transmitThread.start();
1564 * Function called after registering the service in OSGi service registry.
1567 /* get a snapshot of all the existing switches */
1572 * Function called by the dependency manager before the services exported by
1573 * the component are unregistered, this will be followed by a "destroy ()"
1578 shuttingDown = true;
1579 discoveryTimer.cancel();
1580 transmitThread.interrupt();
1584 public void tagUpdated(String containerName, Node n, short oldTag, short newTag, UpdateType t) {
1588 public void containerFlowUpdated(String containerName, ContainerFlow previousFlow, ContainerFlow currentFlow,
1593 public void nodeConnectorUpdated(String containerName, NodeConnector p, UpdateType t) {
1596 moveToReadyListHi(p);
1604 public void containerModeUpdated(UpdateType t) {
1608 private byte[] getSourceMACFromNodeID(String nodeId) {
1609 byte[] cid = HexEncode.bytesFromHexString(nodeId);
1610 byte[] sourceMac = new byte[6];
1611 int pos = cid.length - sourceMac.length;
1614 System.arraycopy(cid, pos, sourceMac, 0, sourceMac.length);
1620 private int getDiscoveryTicks(DiscoveryPeriod dp, String val) {
1627 dp.setTime(Integer.parseInt(val));
1628 } catch (Exception e) {
1632 return dp.getTick();
1636 * This method returns the interval which determines how often the discovery
1637 * packets will be sent.
1639 * @return The discovery interval in ticks
1641 private int getDiscoveryInterval() {
1642 String intvl = System.getProperty("of.discoveryInterval");
1643 return getDiscoveryTicks(DiscoveryPeriod.INTERVAL, intvl);
1647 * This method returns the timeout value in receiving subsequent discovery packets on a port.
1649 * @return The discovery timeout in ticks
1651 private int getDiscoveryTimeout() {
1652 String val = System.getProperty("of.discoveryTimeoutMultiple");
1657 multiple = Integer.parseInt(val);
1658 } catch (Exception e) {
1661 return getDiscoveryInterval() * multiple + 3;
1665 * This method returns the user configurable threshold value
1667 * @return The discovery threshold value in ticks
1669 private int getDiscoveryThreshold() {
1670 String val = System.getProperty("of.discoveryThreshold");
1671 return getDiscoveryTicks(DiscoveryPeriod.THRESHOLD, val);
1675 * This method returns the discovery entry aging time in ticks.
1677 * @return The aging time in ticks
1679 private int getDiscoveryAgeout() {
1680 return getDiscoveryTicks(DiscoveryPeriod.AGEOUT, null);
1684 * This method returns the pause interval
1686 * @return The pause interval in ticks
1688 private int getDiscoveryPauseInterval() {
1689 if (discoveryBatchRestartTicks > discoveryBatchPausePeriod) {
1690 return discoveryBatchRestartTicks - discoveryBatchPausePeriod;
1692 return discoveryBatchRestartTicks - 1;
1697 * This method returns the user configurable maximum number of ports handled
1698 * in one discovery batch.
1700 * @return The maximum number of ports
1702 private int getDiscoveryBatchMaxPorts() {
1703 String val = System.getProperty("of.discoveryBatchMaxPorts");
1708 ports = Integer.parseInt(val);
1709 } catch (Exception e) {