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.openflow.protocol.OFPhysicalPort;
37 import org.osgi.framework.BundleContext;
38 import org.osgi.framework.FrameworkUtil;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
42 import org.opendaylight.controller.sal.core.Config;
43 import org.opendaylight.controller.sal.core.ConstructionException;
44 import org.opendaylight.controller.sal.core.Edge;
45 import org.opendaylight.controller.sal.core.ContainerFlow;
46 import org.opendaylight.controller.sal.core.IContainerListener;
47 import org.opendaylight.controller.sal.core.Node;
48 import org.opendaylight.controller.sal.core.NodeConnector;
49 import org.opendaylight.controller.sal.core.Property;
50 import org.opendaylight.controller.sal.core.State;
51 import org.opendaylight.controller.sal.core.UpdateType;
52 import org.opendaylight.controller.sal.packet.Ethernet;
53 import org.opendaylight.controller.sal.packet.LLDP;
54 import org.opendaylight.controller.sal.packet.LLDPTLV;
55 import org.opendaylight.controller.sal.packet.LinkEncap;
56 import org.opendaylight.controller.sal.packet.PacketResult;
57 import org.opendaylight.controller.sal.packet.RawPacket;
58 import org.opendaylight.controller.sal.utils.EtherTypes;
59 import org.opendaylight.controller.sal.utils.HexEncode;
60 import org.opendaylight.controller.sal.utils.NetUtils;
61 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
62 import org.opendaylight.controller.sal.utils.NodeCreator;
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, portIdTlv, ttlTlv, customTlv;
130 class DiscoveryTransmit implements Runnable {
131 private final BlockingQueue<NodeConnector> transmitQ;
133 DiscoveryTransmit(BlockingQueue<NodeConnector> transmitQ) {
134 this.transmitQ = transmitQ;
141 NodeConnector nodeConnector = transmitQ.take();
142 RawPacket outPkt = createDiscoveryPacket(nodeConnector);
143 sendDiscoveryPacket(nodeConnector, outPkt);
144 nodeConnector = null;
145 } catch (InterruptedException e1) {
146 logger.warn("DiscoveryTransmit interupted", e1.getMessage());
150 } catch (Exception e2) {
151 logger.error("", e2);
157 class DiscoveryTimerTask extends TimerTask {
162 doConsistencyCheck();
167 public enum DiscoveryPeriod {
172 private int time; // sec
173 private int tick; // tick
175 DiscoveryPeriod(int time) {
177 this.tick = time2Tick(time);
180 public int getTime() {
184 public void setTime(int time) {
186 this.tick = time2Tick(time);
189 public int getTick() {
193 public void setTick(int tick) {
194 this.time = tick2Time(tick);
198 private int time2Tick(int time) {
199 return (int) (time / (discoveryTimerTick / 1000));
202 private int tick2Time(int tick) {
203 return (int) (tick * (discoveryTimerTick / 1000));
207 private RawPacket createDiscoveryPacket(NodeConnector nodeConnector) {
208 String nodeId = HexEncode.longToHexString((Long) nodeConnector.getNode().getID());
210 // Create LLDP ChassisID TLV
211 byte[] cidValue = LLDPTLV.createChassisIDTLVValue(nodeId);
212 chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue()).setLength((short) cidValue.length)
215 // Create LLDP PortID TLV
216 String portId = nodeConnector.getNodeConnectorIDString();
217 byte[] pidValue = LLDPTLV.createPortIDTLVValue(portId);
218 portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue()).setLength((short) pidValue.length).setValue(pidValue);
220 // Create LLDP Custom TLV
221 byte[] customValue = LLDPTLV.createCustomTLVValue(nodeConnector.toString());
222 customTlv.setType(LLDPTLV.TLVType.Custom.getValue()).setLength((short) customValue.length)
223 .setValue(customValue);
225 // Create LLDP Custom Option list
226 List<LLDPTLV> customList = new ArrayList<LLDPTLV>();
227 customList.add(customTlv);
229 // Create discovery pkt
230 LLDP discoveryPkt = new LLDP();
231 discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setOptionalTLVList(customList);
233 RawPacket rawPkt = null;
235 // Create ethernet pkt
236 byte[] sourceMac = getSourceMACFromNodeID(nodeId);
237 Ethernet ethPkt = new Ethernet();
238 ethPkt.setSourceMACAddress(sourceMac).setDestinationMACAddress(LLDP.LLDPMulticastMac)
239 .setEtherType(EtherTypes.LLDP.shortValue()).setPayload(discoveryPkt);
241 byte[] data = ethPkt.serialize();
242 rawPkt = new RawPacket(data);
243 rawPkt.setOutgoingNodeConnector(nodeConnector);
244 } catch (ConstructionException cex) {
245 logger.warn("RawPacket creation caught exception {}", cex.getMessage());
246 } catch (Exception e) {
247 logger.error("Failed to serialize the LLDP packet: " + e);
253 private void sendDiscoveryPacket(NodeConnector nodeConnector, RawPacket outPkt) {
254 if (nodeConnector == null) {
255 logger.debug("Can not send discovery packet out since nodeConnector is null");
259 if (outPkt == null) {
260 logger.debug("Can not send discovery packet out since outPkt is null");
264 long sid = (Long) nodeConnector.getNode().getID();
265 ISwitch sw = controller.getSwitches().get(sid);
268 logger.debug("Can not send discovery packet out since switch {} is null", sid);
272 if (!sw.isOperational()) {
273 logger.debug("Can not send discovery packet out since switch {} is not operational", sw);
277 if (this.iDataPacketMux == null) {
278 logger.debug("Can not send discovery packet out since DataPacket service is not available");
282 logger.trace("Sending topology discovery pkt thru {}", nodeConnector);
283 this.iDataPacketMux.transmitDataPacket(outPkt);
287 public PacketResult receiveDataPacket(RawPacket inPkt) {
289 logger.debug("Ignoring null packet");
290 return PacketResult.IGNORED;
293 byte[] data = inPkt.getPacketData();
294 if (data.length <= 0) {
295 logger.trace("Ignoring zero length packet");
296 return PacketResult.IGNORED;
299 if (!inPkt.getEncap().equals(LinkEncap.ETHERNET)) {
300 logger.trace("Ignoring non ethernet packet");
301 return PacketResult.IGNORED;
304 if (((Short) inPkt.getIncomingNodeConnector().getID()).equals(NodeConnector.SPECIALNODECONNECTORID)) {
305 logger.trace("Ignoring ethernet packet received on special port: "
306 + inPkt.getIncomingNodeConnector().toString());
307 return PacketResult.IGNORED;
310 Ethernet ethPkt = new Ethernet();
312 ethPkt.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
313 } catch (Exception e) {
314 logger.warn("Failed to decode LLDP packet from {}: {}", inPkt.getIncomingNodeConnector(), e);
315 return PacketResult.IGNORED;
318 if (ethPkt.getPayload() instanceof LLDP) {
319 NodeConnector dst = inPkt.getIncomingNodeConnector();
320 if (isEnabled(dst)) {
321 if (!processDiscoveryPacket(dst, ethPkt)) {
322 // Snoop the discovery pkt if not generated from us
323 snoopDiscoveryPacket(dst, ethPkt);
325 return PacketResult.CONSUME;
328 return PacketResult.IGNORED;
332 * Snoop incoming discovery frames generated by the production network
335 private void snoopDiscoveryPacket(NodeConnector dstNodeConnector, Ethernet ethPkt) {
336 if (!this.discoverySnoopingEnabled || discoverySnoopingDisableList.contains(dstNodeConnector)) {
337 logger.trace("Discarded received discovery packet on {} since snooping is turned off", dstNodeConnector);
341 if ((dstNodeConnector == null) || (ethPkt == null)) {
342 logger.trace("Quit snooping discovery packet: Null node connector or packet");
346 LLDP lldp = (LLDP) ethPkt.getPayload();
349 String nodeId = LLDPTLV.getHexStringValue(lldp.getChassisId().getValue(), lldp.getChassisId().getLength());
350 String portId = LLDPTLV.getStringValue(lldp.getPortId().getValue(), lldp.getPortId().getLength());
351 byte[] systemNameBytes = null;
352 // get system name if present in the LLDP pkt
353 for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) {
354 if (lldptlv.getType() == LLDPTLV.TLVType.SystemName.getValue()) {
355 systemNameBytes = lldptlv.getValue();
359 String nodeName = (systemNameBytes == null) ? nodeId
360 : new String(systemNameBytes, Charset.defaultCharset());
361 Node srcNode = new Node(Node.NodeIDType.PRODUCTION, nodeName);
362 NodeConnector srcNodeConnector = NodeConnectorCreator.createNodeConnector(
363 NodeConnector.NodeConnectorIDType.PRODUCTION, portId, srcNode);
366 Set<Property> props = null;
367 edge = new Edge(srcNodeConnector, dstNodeConnector);
368 props = getProps(dstNodeConnector);
370 updateProdEdge(edge, props);
371 } catch (Exception e) {
372 logger.warn("Caught exception ", e);
377 * Handle discovery frames generated by our controller
379 * @return true if it's a success
381 private boolean processDiscoveryPacket(NodeConnector dstNodeConnector, Ethernet ethPkt) {
382 if ((dstNodeConnector == null) || (ethPkt == null)) {
383 logger.trace("Ignoring processing of discovery packet: Null node connector or packet");
387 logger.trace("Handle discovery packet {} from {}", ethPkt, dstNodeConnector);
389 LLDP lldp = (LLDP) ethPkt.getPayload();
391 List<LLDPTLV> optionalTLVList = lldp.getOptionalTLVList();
392 if (optionalTLVList == null) {
393 logger.info("The discovery packet with null custom option from {}", dstNodeConnector);
398 NodeConnector srcNodeConnector = null;
399 for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) {
400 if (lldptlv.getType() == LLDPTLV.TLVType.Custom.getValue()) {
401 String ncString = LLDPTLV.getCustomString(lldptlv.getValue(), lldptlv.getLength());
402 srcNodeConnector = NodeConnector.fromString(ncString);
403 if (srcNodeConnector != null) {
404 srcNode = srcNodeConnector.getNode();
409 if ((srcNode == null) || (srcNodeConnector == null)) {
410 logger.trace("Received non-controller generated discovery packet from {}", dstNodeConnector);
414 // push it out to Topology
416 Set<Property> props = null;
418 edge = new Edge(srcNodeConnector, dstNodeConnector);
419 props = getProps(dstNodeConnector);
420 } catch (ConstructionException e) {
421 logger.error("Caught exception ", e);
423 addEdge(edge, props);
425 logger.trace("Received discovery packet for Edge {}", edge);
430 public Map<String, Property> getPropMap(NodeConnector nodeConnector) {
431 if (nodeConnector == null) {
435 if (inventoryProvider == null) {
439 Map<NodeConnector, Map<String, Property>> props = inventoryProvider.getNodeConnectorProps(false);
444 return props.get(nodeConnector);
447 public Property getProp(NodeConnector nodeConnector, String propName) {
448 Map<String, Property> propMap = getPropMap(nodeConnector);
449 if (propMap == null) {
453 Property prop = propMap.get(propName);
457 public Set<Property> getProps(NodeConnector nodeConnector) {
458 Map<String, Property> propMap = getPropMap(nodeConnector);
459 if (propMap == null) {
463 Set<Property> props = new HashSet<Property>(propMap.values());
467 private boolean isEnabled(NodeConnector nodeConnector) {
468 if (nodeConnector == null) {
472 Config config = (Config) getProp(nodeConnector, Config.ConfigPropName);
473 State state = (State) getProp(nodeConnector, State.StatePropName);
474 return ((config != null) && (config.getValue() == Config.ADMIN_UP) && (state != null) && (state.getValue() == State.EDGE_UP));
477 private boolean isTracked(NodeConnector nodeConnector) {
478 if (readyListHi.contains(nodeConnector)) {
482 if (readyListLo.contains(nodeConnector)) {
486 if (holdTime.keySet().contains(nodeConnector)) {
490 if (stagingList.contains(nodeConnector)) {
497 private Set<NodeConnector> getWorkingSet() {
498 Set<NodeConnector> workingSet = new HashSet<NodeConnector>();
499 Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
501 for (NodeConnector nodeConnector : readyListHi) {
502 if (isOverLimit(workingSet.size())) {
506 workingSet.add(nodeConnector);
507 removeSet.add(nodeConnector);
509 // Put it in the map and start the timer. It may need retry.
510 elapsedTime.put(nodeConnector, 0);
512 readyListHi.removeAll(removeSet);
515 for (NodeConnector nodeConnector : readyListLo) {
516 if (isOverLimit(workingSet.size())) {
520 workingSet.add(nodeConnector);
521 removeSet.add(nodeConnector);
523 readyListLo.removeAll(removeSet);
528 private Boolean isOverLimit(int size) {
529 return ((size >= discoveryBatchMaxPorts) && !throttling);
532 private void addDiscovery() {
533 Map<Long, ISwitch> switches = controller.getSwitches();
534 Set<Long> sidSet = switches.keySet();
535 if (sidSet == null) {
538 for (Long sid : sidSet) {
539 Node node = NodeCreator.createOFNode(sid);
544 private void addDiscovery(Node node) {
545 Map<Long, ISwitch> switches = controller.getSwitches();
546 ISwitch sw = switches.get(node.getID());
547 List<OFPhysicalPort> ports = sw.getEnabledPorts();
551 for (OFPhysicalPort port : ports) {
552 NodeConnector nodeConnector = NodeConnectorCreator.createOFNodeConnector(port.getPortNumber(), node);
553 if (!readyListHi.contains(nodeConnector)) {
554 readyListHi.add(nodeConnector);
559 private void addDiscovery(NodeConnector nodeConnector) {
560 if (isTracked(nodeConnector)) {
564 readyListHi.add(nodeConnector);
567 private Set<NodeConnector> getRemoveSet(Collection<NodeConnector> c, Node node) {
568 Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
572 for (NodeConnector nodeConnector : c) {
573 if (node.equals(nodeConnector.getNode())) {
574 Edge edge1 = edgeMap.get(nodeConnector);
576 removeSet.add(nodeConnector);
578 // check reverse direction
579 Edge edge2 = edgeMap.get(edge1.getTailNodeConnector());
580 if ((edge2 != null) && node.equals(edge2.getTailNodeConnector().getNode())) {
581 removeSet.add(edge2.getHeadNodeConnector());
589 private void removeDiscovery(Node node) {
590 Set<NodeConnector> removeSet;
592 removeSet = getRemoveSet(readyListHi, node);
593 readyListHi.removeAll(removeSet);
595 removeSet = getRemoveSet(readyListLo, node);
596 readyListLo.removeAll(removeSet);
598 removeSet = getRemoveSet(stagingList, node);
599 stagingList.removeAll(removeSet);
601 removeSet = getRemoveSet(holdTime.keySet(), node);
602 for (NodeConnector nodeConnector : removeSet) {
603 holdTime.remove(nodeConnector);
606 removeSet = getRemoveSet(edgeMap.keySet(), node);
607 for (NodeConnector nodeConnector : removeSet) {
608 removeEdge(nodeConnector, false);
611 removeSet = getRemoveSet(prodMap.keySet(), node);
612 for (NodeConnector nodeConnector : removeSet) {
613 removeProdEdge(nodeConnector);
617 private void removeDiscovery(NodeConnector nodeConnector) {
618 readyListHi.remove(nodeConnector);
619 readyListLo.remove(nodeConnector);
620 stagingList.remove(nodeConnector);
621 holdTime.remove(nodeConnector);
622 removeEdge(nodeConnector, false);
623 removeProdEdge(nodeConnector);
626 private void checkTimeout() {
627 Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
630 Set<NodeConnector> monitorSet = holdTime.keySet();
631 if (monitorSet != null) {
632 for (NodeConnector nodeConnector : monitorSet) {
633 ticks = holdTime.get(nodeConnector);
634 holdTime.put(nodeConnector, ++ticks);
635 if (ticks >= discoveryTimeoutTicks) {
637 removeSet.add(nodeConnector);
638 logger.trace("Discovery timeout {}", nodeConnector);
643 for (NodeConnector nodeConnector : removeSet) {
644 removeEdge(nodeConnector);
647 Set<NodeConnector> retrySet = new HashSet<NodeConnector>();
648 Set<NodeConnector> ncSet = elapsedTime.keySet();
649 if ((ncSet != null) && (ncSet.size() > 0)) {
650 for (NodeConnector nodeConnector : ncSet) {
651 ticks = elapsedTime.get(nodeConnector);
652 elapsedTime.put(nodeConnector, ++ticks);
653 if (ticks >= discoveryThresholdTicks) {
654 retrySet.add(nodeConnector);
658 for (NodeConnector nodeConnector : retrySet) {
659 // Allow one more retry
660 readyListLo.add(nodeConnector);
661 elapsedTime.remove(nodeConnector);
666 private void checkAging() {
667 if (!discoveryAgingEnabled) {
671 Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
674 Set<NodeConnector> agingSet = agingMap.keySet();
675 if (agingSet != null) {
676 for (NodeConnector nodeConnector : agingSet) {
677 ticks = agingMap.get(nodeConnector);
678 agingMap.put(nodeConnector, ++ticks);
679 if (ticks > discoveryAgeoutTicks) {
681 removeSet.add(nodeConnector);
682 logger.trace("Discovery age out {}", nodeConnector);
687 for (NodeConnector nodeConnector : removeSet) {
688 removeProdEdge(nodeConnector);
692 private void doDiscovery() {
693 if (++discoveryTimerTickCount <= discoveryBatchPauseTicks) {
694 for (NodeConnector nodeConnector : getWorkingSet()) {
695 transmitQ.add(nodeConnector);
696 // Move to staging area after it's served
697 if (!stagingList.contains(nodeConnector)) {
698 stagingList.add(nodeConnector);
701 } else if (discoveryTimerTickCount >= discoveryBatchRestartTicks) {
702 discoveryTimerTickCount = 0;
703 for (NodeConnector nodeConnector : stagingList) {
704 if (!readyListLo.contains(nodeConnector)) {
705 readyListLo.add(nodeConnector);
708 stagingList.removeAll(readyListLo);
712 private void doConsistencyCheck() {
713 if (!discoveryConsistencyCheckEnabled) {
717 if (++discoveryConsistencyCheckTickCount % getDiscoveryConsistencyCheckInterval() != 0) {
721 discoveryConsistencyCheckCallingTimes++;
723 Set<NodeConnector> removeSet = new HashSet<NodeConnector>();
724 Set<NodeConnector> ncSet = edgeMap.keySet();
728 for (NodeConnector nodeConnector : ncSet) {
729 if (!isEnabled(nodeConnector)) {
730 removeSet.add(nodeConnector);
731 discoveryConsistencyCheckCorrected++;
732 logger.debug("ConsistencyChecker: remove disabled {}", nodeConnector);
736 if (!isTracked(nodeConnector)) {
737 stagingList.add(nodeConnector);
738 discoveryConsistencyCheckCorrected++;
739 logger.debug("ConsistencyChecker: add back untracked {}", nodeConnector);
744 for (NodeConnector nodeConnector : removeSet) {
745 removeEdge(nodeConnector, false);
748 // remove stale entries
750 for (NodeConnector nodeConnector : stagingList) {
751 if (!isEnabled(nodeConnector)) {
752 removeSet.add(nodeConnector);
753 discoveryConsistencyCheckCorrected++;
754 logger.debug("ConsistencyChecker: remove disabled {}", nodeConnector);
757 stagingList.removeAll(removeSet);
759 // Get a snapshot of all the existing switches
760 Map<Long, ISwitch> switches = this.controller.getSwitches();
761 for (ISwitch sw : switches.values()) {
762 for (OFPhysicalPort port : sw.getEnabledPorts()) {
763 Node node = NodeCreator.createOFNode(sw.getId());
764 NodeConnector nodeConnector = NodeConnectorCreator.createOFNodeConnector(port.getPortNumber(), node);
765 if (!isTracked(nodeConnector)) {
766 stagingList.add(nodeConnector);
767 discoveryConsistencyCheckCorrected++;
768 logger.debug("ConsistencyChecker: add back untracked {}", nodeConnector);
774 private void addEdge(Edge edge, Set<Property> props) {
779 NodeConnector src = edge.getTailNodeConnector();
780 NodeConnector dst = edge.getHeadNodeConnector();
781 if (!src.getType().equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) {
782 holdTime.put(dst, 0);
784 agingMap.put(dst, 0);
786 elapsedTime.remove(src);
789 updateEdge(edge, UpdateType.ADDED, props);
790 logger.trace("Add edge {}", edge);
794 * Update Production Edge
797 * The Production Edge
799 * Properties associated with the edge
801 private void updateProdEdge(Edge edge, Set<Property> props) {
802 NodeConnector edgePort = edge.getHeadNodeConnector();
804 /* Do not update in case there is an existing OpenFlow link */
805 if (edgeMap.get(edgePort) != null) {
806 logger.trace("Discarded edge {} since there is an existing OF link {}", edge, edgeMap.get(edgePort));
810 /* Look for any existing Production Edge */
811 Edge oldEdge = prodMap.get(edgePort);
812 if (oldEdge == null) {
813 /* Let's add a new one */
814 addEdge(edge, props);
815 } else if (!edge.equals(oldEdge)) {
816 /* Remove the old one first */
817 removeProdEdge(oldEdge.getHeadNodeConnector());
818 /* Then add the new one */
819 addEdge(edge, props);
821 /* o/w, just reset the aging timer */
822 NodeConnector dst = edge.getHeadNodeConnector();
823 agingMap.put(dst, 0);
828 * Remove Production Edge for a given edge port
833 private void removeProdEdge(NodeConnector edgePort) {
834 agingMap.remove(edgePort);
837 Set<NodeConnector> prodKeySet = prodMap.keySet();
838 if ((prodKeySet != null) && (prodKeySet.contains(edgePort))) {
839 edge = prodMap.get(edgePort);
840 prodMap.remove(edgePort);
844 if (this.discoveryListener != null) {
845 this.discoveryListener.notifyEdge(edge, UpdateType.REMOVED, null);
847 logger.trace("Remove edge {}", edge);
851 * Remove OpenFlow edge
853 private void removeEdge(NodeConnector nodeConnector, boolean stillEnabled) {
854 holdTime.remove(nodeConnector);
855 readyListLo.remove(nodeConnector);
856 readyListHi.remove(nodeConnector);
860 if (!stagingList.contains(nodeConnector)) {
861 stagingList.add(nodeConnector);
865 stagingList.remove(nodeConnector);
869 Set<NodeConnector> edgeKeySet = edgeMap.keySet();
870 if ((edgeKeySet != null) && (edgeKeySet.contains(nodeConnector))) {
871 edge = edgeMap.get(nodeConnector);
872 edgeMap.remove(nodeConnector);
876 if (this.discoveryListener != null) {
877 this.discoveryListener.notifyEdge(edge, UpdateType.REMOVED, null);
879 logger.trace("Remove {}", nodeConnector);
882 private void removeEdge(NodeConnector nodeConnector) {
883 removeEdge(nodeConnector, isEnabled(nodeConnector));
886 private void updateEdge(Edge edge, UpdateType type, Set<Property> props) {
887 if (discoveryListener == null) {
891 this.discoveryListener.notifyEdge(edge, type, props);
893 NodeConnector src = edge.getTailNodeConnector(), dst = edge.getHeadNodeConnector();
894 if (!src.getType().equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) {
895 if (type == UpdateType.ADDED) {
896 edgeMap.put(dst, edge);
902 * Save Production edge into different DB keyed by the Edge port
904 if (type == UpdateType.ADDED) {
905 prodMap.put(dst, edge);
912 private void moveToReadyListHi(NodeConnector nodeConnector) {
913 if (readyListLo.contains(nodeConnector)) {
914 readyListLo.remove(nodeConnector);
915 } else if (stagingList.contains(nodeConnector)) {
916 stagingList.remove(nodeConnector);
918 readyListHi.add(nodeConnector);
921 private void registerWithOSGIConsole() {
922 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
923 bundleContext.registerService(CommandProvider.class.getName(), this, null);
926 private int getDiscoveryConsistencyCheckInterval() {
927 return discoveryConsistencyCheckMultiple * discoveryBatchRestartTicks;
931 public String getHelp() {
932 StringBuffer help = new StringBuffer();
933 help.append("---Topology Discovery---\n");
934 help.append("\t prlh - Print readyListHi entries\n");
935 help.append("\t prll - Print readyListLo entries\n");
936 help.append("\t psl - Print stagingList entries\n");
937 help.append("\t pht - Print hold time\n");
938 help.append("\t pet - Print elapsed time\n");
939 help.append("\t ptick - Print tick time in msec\n");
940 help.append("\t pcc - Print CC info\n");
941 help.append("\t psize - Print sizes of all the lists\n");
942 help.append("\t ptm - Print timeout info\n");
943 help.append("\t ecc - Enable CC\n");
944 help.append("\t dcc - Disable CC\n");
945 help.append("\t scc [multiple] - Set/show CC multiple and interval\n");
946 help.append("\t sports [ports] - Set/show max ports per batch\n");
947 help.append("\t spause [ticks] - Set/show pause period\n");
948 help.append("\t sdi [ticks] - Set/show discovery interval in ticks\n");
949 help.append("\t addsw <swid> - Add a switch\n");
950 help.append("\t remsw <swid> - Remove a switch\n");
951 help.append("\t page - Print aging info\n");
952 help.append("\t sage - Set/Show aging time limit\n");
953 help.append("\t eage - Enable aging\n");
954 help.append("\t dage - Disable aging\n");
955 help.append("\t pthrot - Print throttling\n");
956 help.append("\t ethrot - Enable throttling\n");
957 help.append("\t dthrot - Disable throttling\n");
958 help.append("\t psnp - Print LLDP snooping\n");
959 help.append("\t esnp <all|nodeConnector> - Enable LLDP snooping\n");
960 help.append("\t dsnp <all|nodeConnector> - Disable LLDP snooping\n");
961 return help.toString();
964 private List<NodeConnector> sortList(Collection<NodeConnector> ncs) {
965 List<String> ncStrArray = new ArrayList<String>();
966 for (NodeConnector nc : ncs) {
967 ncStrArray.add(nc.toString());
969 Collections.sort(ncStrArray);
971 List<NodeConnector> sortedNodeConnectors = new ArrayList<NodeConnector>();
972 for (String ncStr : ncStrArray) {
973 sortedNodeConnectors.add(NodeConnector.fromString(ncStr));
976 return sortedNodeConnectors;
979 public void _prlh(CommandInterpreter ci) {
980 ci.println("readyListHi\n");
981 for (NodeConnector nodeConnector : sortList(readyListHi)) {
982 if (nodeConnector == null) {
985 ci.println(nodeConnector);
987 ci.println("Total number of Node Connectors: " + readyListHi.size());
990 public void _prll(CommandInterpreter ci) {
991 ci.println("readyListLo\n");
992 for (NodeConnector nodeConnector : sortList(readyListLo)) {
993 if (nodeConnector == null) {
996 ci.println(nodeConnector);
998 ci.println("Total number of Node Connectors: " + readyListLo.size());
1001 public void _psl(CommandInterpreter ci) {
1002 ci.println("stagingList\n");
1003 for (NodeConnector nodeConnector : sortList(stagingList)) {
1004 if (nodeConnector == null) {
1007 ci.println(nodeConnector);
1009 ci.println("Total number of Node Connectors: " + stagingList.size());
1012 public void _pht(CommandInterpreter ci) {
1013 ci.println(" NodeConnector Last rx LLDP (sec)");
1014 for (ConcurrentMap.Entry<NodeConnector, Integer> entry: holdTime.entrySet()) {
1015 ci.println(entry.getKey() + "\t\t" + entry.getValue() * (discoveryTimerTick / 1000));
1017 ci.println("\nSize: " + holdTime.size() + "\tTimeout: " + discoveryTimeoutTicks * (discoveryTimerTick / 1000)
1021 public void _pet(CommandInterpreter ci) {
1022 ci.println(" NodeConnector Elapsed Time (sec)");
1023 for (ConcurrentMap.Entry<NodeConnector, Integer> entry: elapsedTime.entrySet()) {
1024 ci.println(entry.getKey() + "\t\t" + entry.getValue() * (discoveryTimerTick / 1000));
1026 ci.println("\nSize: " + elapsedTime.size() + "\tThreshold: " + DiscoveryPeriod.THRESHOLD.getTime() + " sec");
1029 public void _ptick(CommandInterpreter ci) {
1030 ci.println("Current timer is " + discoveryTimerTick + " msec per tick");
1033 public void _pcc(CommandInterpreter ci) {
1034 if (discoveryConsistencyCheckEnabled) {
1035 ci.println("ConsistencyChecker is currently enabled");
1037 ci.println("ConsistencyChecker is currently disabled");
1039 ci.println("Interval " + getDiscoveryConsistencyCheckInterval());
1040 ci.println("Multiple " + discoveryConsistencyCheckMultiple);
1041 ci.println("Number of times called " + discoveryConsistencyCheckCallingTimes);
1042 ci.println("Corrected count " + discoveryConsistencyCheckCorrected);
1045 public void _ptm(CommandInterpreter ci) {
1046 ci.println("Timeout " + discoveryTimeoutTicks + " ticks, " + discoveryTimerTick / 1000 + " sec per tick.");
1049 public void _psize(CommandInterpreter ci) {
1050 ci.println("readyListLo size " + readyListLo.size() + "\n" + "readyListHi size " + readyListHi.size() + "\n"
1051 + "stagingList size " + stagingList.size() + "\n" + "holdTime size " + holdTime.size() + "\n"
1052 + "edgeMap size " + edgeMap.size() + "\n" + "prodMap size " + prodMap.size() + "\n" + "agingMap size "
1053 + agingMap.size() + "\n" + "elapsedTime size " + elapsedTime.size());
1056 public void _page(CommandInterpreter ci) {
1057 if (this.discoveryAgingEnabled) {
1058 ci.println("Aging is enabled");
1060 ci.println("Aging is disabled");
1062 ci.println("Current aging time limit " + this.discoveryAgeoutTicks);
1064 ci.println(" Edge Aging ");
1065 Collection<Edge> prodSet = prodMap.values();
1066 if (prodSet == null) {
1069 for (Edge edge : prodSet) {
1070 Integer aging = agingMap.get(edge.getHeadNodeConnector());
1071 if (aging != null) {
1072 ci.println(edge + " " + aging);
1076 ci.println(" NodeConnector Edge ");
1077 Set<NodeConnector> keySet = prodMap.keySet();
1078 if (keySet == null) {
1081 for (NodeConnector nc : keySet) {
1082 ci.println(nc + " " + prodMap.get(nc));
1087 public void _sage(CommandInterpreter ci) {
1088 String val = ci.nextArgument();
1090 ci.println("Please enter aging time limit. Current value " + this.discoveryAgeoutTicks);
1094 this.discoveryAgeoutTicks = Integer.parseInt(val);
1095 } catch (Exception e) {
1096 ci.println("Please enter a valid number");
1101 public void _eage(CommandInterpreter ci) {
1102 this.discoveryAgingEnabled = true;
1103 ci.println("Aging is enabled");
1107 public void _dage(CommandInterpreter ci) {
1108 this.discoveryAgingEnabled = false;
1109 ci.println("Aging is disabled");
1113 public void _scc(CommandInterpreter ci) {
1114 String val = ci.nextArgument();
1116 ci.println("Please enter CC multiple. Current multiple " + discoveryConsistencyCheckMultiple
1117 + " (interval " + getDiscoveryConsistencyCheckInterval() + ") calling times "
1118 + discoveryConsistencyCheckCallingTimes);
1122 discoveryConsistencyCheckMultiple = Integer.parseInt(val);
1123 } catch (Exception e) {
1124 ci.println("Please enter a valid number");
1129 public void _ecc(CommandInterpreter ci) {
1130 this.discoveryConsistencyCheckEnabled = true;
1131 ci.println("ConsistencyChecker is enabled");
1135 public void _dcc(CommandInterpreter ci) {
1136 this.discoveryConsistencyCheckEnabled = false;
1137 ci.println("ConsistencyChecker is disabled");
1141 public void _psnp(CommandInterpreter ci) {
1142 if (this.discoverySnoopingEnabled) {
1143 ci.println("Discovery snooping is globally enabled");
1145 ci.println("Discovery snooping is globally disabled");
1148 ci.println("\nDiscovery snooping is locally disabled on these ports");
1149 for (NodeConnector nodeConnector : discoverySnoopingDisableList) {
1150 ci.println(nodeConnector);
1155 public void _esnp(CommandInterpreter ci) {
1156 String val = ci.nextArgument();
1159 ci.println("Usage: esnp <all|nodeConnector>");
1160 } else if (val.equalsIgnoreCase("all")) {
1161 this.discoverySnoopingEnabled = true;
1162 ci.println("Discovery snooping is globally enabled");
1164 NodeConnector nodeConnector = NodeConnector.fromString(val);
1165 if (nodeConnector != null) {
1166 discoverySnoopingDisableList.remove(nodeConnector);
1167 ci.println("Discovery snooping is locally enabled on port " + nodeConnector);
1169 ci.println("Entered invalid NodeConnector " + val);
1175 public void _dsnp(CommandInterpreter ci) {
1176 String val = ci.nextArgument();
1179 ci.println("Usage: dsnp <all|nodeConnector>");
1180 } else if (val.equalsIgnoreCase("all")) {
1181 this.discoverySnoopingEnabled = false;
1182 ci.println("Discovery snooping is globally disabled");
1184 NodeConnector nodeConnector = NodeConnector.fromString(val);
1185 if (nodeConnector != null) {
1186 discoverySnoopingDisableList.add(nodeConnector);
1187 ci.println("Discovery snooping is locally disabled on port " + nodeConnector);
1189 ci.println("Entered invalid NodeConnector " + val);
1195 public void _spause(CommandInterpreter ci) {
1196 String val = ci.nextArgument();
1197 String out = "Please enter pause period less than " + discoveryBatchRestartTicks + ". Current pause period is "
1198 + discoveryBatchPausePeriod + " ticks, pause at " + discoveryBatchPauseTicks + " ticks, "
1199 + discoveryTimerTick / 1000 + " sec per tick.";
1203 int pause = Integer.parseInt(val);
1204 if (pause < discoveryBatchRestartTicks) {
1205 discoveryBatchPausePeriod = pause;
1206 discoveryBatchPauseTicks = getDiscoveryPauseInterval();
1209 } catch (Exception e) {
1216 public void _sdi(CommandInterpreter ci) {
1217 String val = ci.nextArgument();
1218 String out = "Please enter discovery interval in ticks. Current value is " + discoveryBatchRestartTicks + " ticks, "
1219 + discoveryTimerTick / 1000 + " sec per tick.";
1223 int ticks = Integer.parseInt(val);
1224 DiscoveryPeriod.INTERVAL.setTick(ticks);
1225 discoveryBatchRestartTicks = getDiscoveryInterval();
1226 discoveryBatchPauseTicks = getDiscoveryPauseInterval();
1227 discoveryTimeoutTicks = getDiscoveryTimeout();
1229 } catch (Exception e) {
1235 public void _sports(CommandInterpreter ci) {
1236 String val = ci.nextArgument();
1238 ci.println("Please enter max ports per batch. Current value is " + discoveryBatchMaxPorts);
1242 discoveryBatchMaxPorts = Integer.parseInt(val);
1243 } catch (Exception e) {
1244 ci.println("Please enter a valid number");
1249 public void _addsw(CommandInterpreter ci) {
1250 String val = ci.nextArgument();
1253 sid = Long.parseLong(val);
1254 Node node = NodeCreator.createOFNode(sid);
1256 } catch (Exception e) {
1257 ci.println("Please enter a valid number");
1262 public void _remsw(CommandInterpreter ci) {
1263 String val = ci.nextArgument();
1266 sid = Long.parseLong(val);
1267 Node node = NodeCreator.createOFNode(sid);
1268 removeDiscovery(node);
1269 } catch (Exception e) {
1270 ci.println("Please enter a valid number");
1275 public void _pthrot(CommandInterpreter ci) {
1276 if (this.throttling) {
1277 ci.println("Throttling is enabled");
1279 ci.println("Throttling is disabled");
1283 public void _ethrot(CommandInterpreter ci) {
1284 this.throttling = true;
1285 ci.println("Throttling is enabled");
1289 public void _dthrot(CommandInterpreter ci) {
1290 this.throttling = false;
1291 ci.println("Throttling is disabled");
1296 public void updateNode(Node node, UpdateType type, Set<Property> props) {
1299 addNode(node, props);
1310 public void updateNodeConnector(NodeConnector nodeConnector, UpdateType type, Set<Property> props) {
1311 Config config = null;
1313 boolean enabled = false;
1315 for (Property prop : props) {
1316 if (prop.getName().equals(Config.ConfigPropName)) {
1317 config = (Config) prop;
1318 } else if (prop.getName().equals(State.StatePropName)) {
1319 state = (State) prop;
1322 enabled = ((config != null) && (config.getValue() == Config.ADMIN_UP) && (state != null) && (state.getValue() == State.EDGE_UP));
1327 addDiscovery(nodeConnector);
1328 logger.trace("ADDED enabled {}", nodeConnector);
1330 logger.trace("ADDED disabled {}", nodeConnector);
1335 addDiscovery(nodeConnector);
1336 logger.trace("CHANGED enabled {}", nodeConnector);
1338 removeDiscovery(nodeConnector);
1339 logger.trace("CHANGED disabled {}", nodeConnector);
1343 removeDiscovery(nodeConnector);
1344 logger.trace("REMOVED enabled {}", nodeConnector);
1351 public void addNode(Node node, Set<Property> props) {
1359 public void removeNode(Node node) {
1364 removeDiscovery(node);
1367 void setController(IController s) {
1368 this.controller = s;
1371 void unsetController(IController s) {
1372 if (this.controller == s) {
1373 this.controller = null;
1377 public void setInventoryProvider(IInventoryProvider service) {
1378 this.inventoryProvider = service;
1381 public void unsetInventoryProvider(IInventoryProvider service) {
1382 this.inventoryProvider = null;
1385 public void setIDataPacketMux(IDataPacketMux service) {
1386 this.iDataPacketMux = service;
1389 public void unsetIDataPacketMux(IDataPacketMux service) {
1390 if (this.iDataPacketMux == service) {
1391 this.iDataPacketMux = null;
1395 void setDiscoveryListener(IDiscoveryListener s) {
1396 this.discoveryListener = s;
1399 void unsetDiscoveryListener(IDiscoveryListener s) {
1400 if (this.discoveryListener == s) {
1401 this.discoveryListener = null;
1405 private void initDiscoveryPacket() {
1406 // Create LLDP ChassisID TLV
1407 chassisIdTlv = new LLDPTLV();
1408 chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue());
1410 // Create LLDP PortID TLV
1411 portIdTlv = new LLDPTLV();
1412 portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue());
1414 // Create LLDP TTL TLV
1415 byte[] ttl = new byte[] { (byte) 0, (byte) 120 };
1416 ttlTlv = new LLDPTLV();
1417 ttlTlv.setType(LLDPTLV.TLVType.TTL.getValue()).setLength((short) ttl.length).setValue(ttl);
1419 customTlv = new LLDPTLV();
1423 * Function called by the dependency manager when all the required
1424 * dependencies are satisfied
1428 logger.trace("Init called");
1430 transmitQ = new LinkedBlockingQueue<NodeConnector>();
1432 readyListHi = new CopyOnWriteArrayList<NodeConnector>();
1433 readyListLo = new CopyOnWriteArrayList<NodeConnector>();
1434 stagingList = new CopyOnWriteArrayList<NodeConnector>();
1435 holdTime = new ConcurrentHashMap<NodeConnector, Integer>();
1436 elapsedTime = new ConcurrentHashMap<NodeConnector, Integer>();
1437 edgeMap = new ConcurrentHashMap<NodeConnector, Edge>();
1438 agingMap = new ConcurrentHashMap<NodeConnector, Integer>();
1439 prodMap = new ConcurrentHashMap<NodeConnector, Edge>();
1440 discoverySnoopingDisableList = new CopyOnWriteArrayList<NodeConnector>();
1442 discoveryBatchRestartTicks = getDiscoveryInterval();
1443 discoveryBatchPauseTicks = getDiscoveryPauseInterval();
1444 discoveryTimeoutTicks = getDiscoveryTimeout();
1445 discoveryThresholdTicks = getDiscoveryThreshold();
1446 discoveryAgeoutTicks = getDiscoveryAgeout();
1447 discoveryConsistencyCheckTickCount = discoveryBatchPauseTicks;
1448 discoveryBatchMaxPorts = getDiscoveryBatchMaxPorts();
1450 discoveryTimer = new Timer("DiscoveryService");
1451 discoveryTimerTask = new DiscoveryTimerTask();
1453 transmitThread = new Thread(new DiscoveryTransmit(transmitQ));
1455 initDiscoveryPacket();
1457 registerWithOSGIConsole();
1461 * Function called by the dependency manager when at least one dependency
1462 * become unsatisfied or when the component is shutting down because for
1463 * example bundle is being stopped.
1475 discoveryTimer = null;
1476 discoveryTimerTask = null;
1477 transmitThread = null;
1481 * Function called by dependency manager after "init ()" is called and after
1482 * the services provided by the class are registered in the service registry
1486 discoveryTimer.schedule(discoveryTimerTask, discoveryTimerTick, discoveryTimerTick);
1487 transmitThread.start();
1491 * Function called after registering the service in OSGi service registry.
1494 /* get a snapshot of all the existing switches */
1499 * Function called by the dependency manager before the services exported by
1500 * the component are unregistered, this will be followed by a "destroy ()"
1505 shuttingDown = true;
1506 discoveryTimer.cancel();
1507 transmitThread.interrupt();
1511 public void tagUpdated(String containerName, Node n, short oldTag, short newTag, UpdateType t) {
1515 public void containerFlowUpdated(String containerName, ContainerFlow previousFlow, ContainerFlow currentFlow,
1520 public void nodeConnectorUpdated(String containerName, NodeConnector p, UpdateType t) {
1523 moveToReadyListHi(p);
1531 public void containerModeUpdated(UpdateType t) {
1535 private byte[] getSourceMACFromNodeID(String nodeId) {
1536 byte[] cid = HexEncode.bytesFromHexString(nodeId);
1537 byte[] sourceMac = new byte[6];
1538 int pos = cid.length - sourceMac.length;
1541 System.arraycopy(cid, pos, sourceMac, 0, sourceMac.length);
1547 private int getDiscoveryTicks(DiscoveryPeriod dp, String val) {
1554 dp.setTime(Integer.parseInt(val));
1555 } catch (Exception e) {
1559 return dp.getTick();
1563 * This method returns the interval which determines how often the discovery
1564 * packets will be sent.
1566 * @return The discovery interval in ticks
1568 private int getDiscoveryInterval() {
1569 String intvl = System.getProperty("of.discoveryInterval");
1570 return getDiscoveryTicks(DiscoveryPeriod.INTERVAL, intvl);
1574 * This method returns the timeout value in receiving subsequent discovery packets on a port.
1576 * @return The discovery timeout in ticks
1578 private int getDiscoveryTimeout() {
1579 String val = System.getProperty("of.discoveryTimeoutMultiple");
1584 multiple = Integer.parseInt(val);
1585 } catch (Exception e) {
1588 return getDiscoveryInterval() * multiple + 3;
1592 * This method returns the user configurable threshold value
1594 * @return The discovery threshold value in ticks
1596 private int getDiscoveryThreshold() {
1597 String val = System.getProperty("of.discoveryThreshold");
1598 return getDiscoveryTicks(DiscoveryPeriod.THRESHOLD, val);
1602 * This method returns the discovery entry aging time in ticks.
1604 * @return The aging time in ticks
1606 private int getDiscoveryAgeout() {
1607 return getDiscoveryTicks(DiscoveryPeriod.AGEOUT, null);
1611 * This method returns the pause interval
1613 * @return The pause interval in ticks
1615 private int getDiscoveryPauseInterval() {
1616 if (discoveryBatchRestartTicks > discoveryBatchPausePeriod) {
1617 return discoveryBatchRestartTicks - discoveryBatchPausePeriod;
1619 return discoveryBatchRestartTicks - 1;
1624 * This method returns the user configurable maximum number of ports handled
1625 * in one discovery batch.
1627 * @return The maximum number of ports
1629 private int getDiscoveryBatchMaxPorts() {
1630 String val = System.getProperty("of.discoveryBatchMaxPorts");
1635 ports = Integer.parseInt(val);
1636 } catch (Exception e) {