X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fprotocol_plugins%2Fopenflow%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fprotocol_plugin%2Fopenflow%2Finternal%2FDiscoveryService.java;h=548bfb1f9fb26eb93ab4ca5bcd456d9bdc4082c3;hp=eab87a4440b356d0f734061505897e3115d87d8e;hb=3037a8b4158f8e4dbb891047180c5b1a9a0e053b;hpb=d192c699590d441eb96a697b9e8ab7a028f18860 diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java index eab87a4440..548bfb1f9f 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/DiscoveryService.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -9,8 +8,10 @@ package org.opendaylight.controller.protocol_plugin.openflow.internal; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -27,27 +28,22 @@ import org.eclipse.osgi.framework.console.CommandInterpreter; import org.eclipse.osgi.framework.console.CommandProvider; import org.opendaylight.controller.protocol_plugin.openflow.IDataPacketListen; import org.opendaylight.controller.protocol_plugin.openflow.IDataPacketMux; +import org.opendaylight.controller.protocol_plugin.openflow.IDiscoveryListener; +import org.opendaylight.controller.protocol_plugin.openflow.IInventoryProvider; import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener; import org.opendaylight.controller.protocol_plugin.openflow.core.IController; import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch; -import org.openflow.protocol.OFPhysicalPort; -import org.osgi.framework.BundleContext; -import org.osgi.framework.FrameworkUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - +import org.opendaylight.controller.sal.connection.IPluginOutConnectionService; import org.opendaylight.controller.sal.core.Config; import org.opendaylight.controller.sal.core.ConstructionException; -import org.opendaylight.controller.sal.core.Edge; import org.opendaylight.controller.sal.core.ContainerFlow; +import org.opendaylight.controller.sal.core.Edge; import org.opendaylight.controller.sal.core.IContainerListener; import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.core.NodeConnector; import org.opendaylight.controller.sal.core.Property; import org.opendaylight.controller.sal.core.State; import org.opendaylight.controller.sal.core.UpdateType; -import org.opendaylight.controller.sal.discovery.IDiscoveryService; -import org.opendaylight.controller.sal.inventory.IPluginInInventoryService; import org.opendaylight.controller.sal.packet.Ethernet; import org.opendaylight.controller.sal.packet.LLDP; import org.opendaylight.controller.sal.packet.LLDPTLV; @@ -59,60 +55,88 @@ import org.opendaylight.controller.sal.utils.HexEncode; import org.opendaylight.controller.sal.utils.NetUtils; import org.opendaylight.controller.sal.utils.NodeConnectorCreator; import org.opendaylight.controller.sal.utils.NodeCreator; +import org.openflow.protocol.OFPhysicalPort; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The class describes neighbor discovery service for an OpenFlow network. */ -public class DiscoveryService implements IInventoryShimExternalListener, - IDataPacketListen, IContainerListener, CommandProvider { - private static Logger logger = LoggerFactory - .getLogger(DiscoveryService.class); +public class DiscoveryService implements IInventoryShimExternalListener, IDataPacketListen, IContainerListener, + CommandProvider { + private static Logger logger = LoggerFactory.getLogger(DiscoveryService.class); private IController controller = null; - private IDiscoveryService discoveryService = null; - private IPluginInInventoryService pluginInInventoryService = null; + private IDiscoveryListener discoveryListener = null; + private IInventoryProvider inventoryProvider = null; private IDataPacketMux iDataPacketMux = null; - - private List readyListHi = null; // newly added ports go into this list and will be served first - private List readyListLo = null; // come here after served at least once - private List waitingList = null; // staging area during quiet period - private ConcurrentMap pendingMap = null;// wait for response back - private ConcurrentMap edgeMap = null; // openflow edges keyed by head connector - private ConcurrentMap agingMap = null; // aging entries keyed by edge port - private ConcurrentMap prodMap = null; // production edges keyed by edge port - - private Timer discoveryTimer; // discovery timer - private DiscoveryTimerTask discoveryTimerTask; // timer task - private long discoveryTimerTick = 1L * 1000; // per tick in msec + // High priority list containing newly added ports which will be served first + private List readyListHi = null; + // List containing all the ports which will be served periodically + private List readyListLo = null; + // Staging area during quiet period + private List stagingList = null; + // Wait for next discovery packet. The map contains the time elapsed since + // the last received LLDP frame on each node connector + private ConcurrentMap holdTime = null; + // Allow one more retry for newly added ports. This map contains the time + // period elapsed since last discovery pkt transmission on the port. + private ConcurrentMap elapsedTime = null; + // OpenFlow edges keyed by head connector + private ConcurrentMap edgeMap = null; + // The map contains aging entry keyed by head connector of Production edge + private ConcurrentMap agingMap = null; + // Production edges keyed by head connector + private ConcurrentMap prodMap = null; + + private Timer discoveryTimer; + private DiscoveryTimerTask discoveryTimerTask; + private final static long discoveryTimerTick = 2L * 1000; // per tick in msec private int discoveryTimerTickCount = 0; // main tick counter - private int discoveryBatchMaxPorts = 500; // max # of ports handled in one batch - private int discoveryBatchRestartTicks = 30; // periodically restart batching process - private int discoveryBatchPausePeriod = 2; // pause for few secs - private int discoveryBatchPauseTicks = discoveryBatchRestartTicks - discoveryBatchPausePeriod; // pause after this point - private int discoveryRetry = 1; // number of retry after initial timeout - private int discoveryTimeoutTicks = 2; // timeout 2 sec - private int discoveryAgeoutTicks = 120; // age out 2 min - private int discoveryConsistencyCheckMultiple = 2; // multiple of discoveryBatchRestartTicks - private int discoveryConsistencyCheckTickCount = discoveryBatchPauseTicks; // CC tick counter - private int discoveryConsistencyCheckCallingTimes = 0; // # of times CC gets called - private int discoveryConsistencyCheckCorrected = 0; // # of cases CC corrected - private boolean discoveryConsistencyCheckEnabled = true;// enable or disable CC - private boolean discoveryAgingEnabled = true; // enable or disable aging - private boolean discoverySpoofingEnabled = true; // enable or disable spoofing neighbor of a production network - + // Max # of ports handled in one batch + private int discoveryBatchMaxPorts; + // Periodically restart batching process + private int discoveryBatchRestartTicks; + private int discoveryBatchPausePeriod = 2; + // Pause after this point + private int discoveryBatchPauseTicks; + private int discoveryTimeoutTicks; + private int discoveryThresholdTicks; + private int discoveryAgeoutTicks; + // multiple of discoveryBatchRestartTicks + private int discoveryConsistencyCheckMultiple = 2; + // CC tick counter + private int discoveryConsistencyCheckTickCount; + // # of times CC gets called + private int discoveryConsistencyCheckCallingTimes = 0; + // # of cases CC corrected + private int discoveryConsistencyCheckCorrected = 0; + // Enable or disable CC + private boolean discoveryConsistencyCheckEnabled = true; + // Enable or disable aging + private boolean discoveryAgingEnabled = true; + // Global flag to enable or disable LLDP snooping + private boolean discoverySnoopingEnabled = true; + // The list of ports that will not do LLDP snooping + private List discoverySnoopingDisableList; private BlockingQueue transmitQ; private Thread transmitThread; private Boolean throttling = false; // if true, no more batching. private volatile Boolean shuttingDown = false; - private LLDPTLV chassisIdTlv, portIdTlv, ttlTlv, customTlv; + private LLDPTLV chassisIdTlv, systemNameTlv, portIdTlv, ttlTlv, customTlv; + private IPluginOutConnectionService connectionOutService; class DiscoveryTransmit implements Runnable { private final BlockingQueue transmitQ; + private int count = 0; DiscoveryTransmit(BlockingQueue transmitQ) { this.transmitQ = transmitQ; } + @Override public void run() { while (true) { try { @@ -120,20 +144,23 @@ public class DiscoveryService implements IInventoryShimExternalListener, RawPacket outPkt = createDiscoveryPacket(nodeConnector); sendDiscoveryPacket(nodeConnector, outPkt); nodeConnector = null; + if ((++count & 0x7f) == 0) { + Thread.sleep(10); + } } catch (InterruptedException e1) { - logger - .warn("DiscoveryTransmit interupted", e1 - .getMessage()); - if (shuttingDown) + logger.warn("DiscoveryTransmit interupted", e1.getMessage()); + if (shuttingDown) { return; + } } catch (Exception e2) { - logger.error("",e2); + logger.error("", e2); } } } } class DiscoveryTimerTask extends TimerTask { + @Override public void run() { checkTimeout(); checkAging(); @@ -142,25 +169,68 @@ public class DiscoveryService implements IInventoryShimExternalListener, } } + public enum DiscoveryPeriod { + INTERVAL (300), + AGEOUT (120), + THRESHOLD (30); + + private int time; // sec + private int tick; // tick + + DiscoveryPeriod(int time) { + this.time = time; + this.tick = time2Tick(time); + } + + public int getTime() { + return time; + } + + public void setTime(int time) { + this.time = time; + this.tick = time2Tick(time); + } + + public int getTick() { + return tick; + } + + public void setTick(int tick) { + this.time = tick2Time(tick); + this.tick = tick; + } + + private int time2Tick(int time) { + return (int) (time / (discoveryTimerTick / 1000)); + } + + private int tick2Time(int tick) { + return (int) (tick * (discoveryTimerTick / 1000)); + } + } + private RawPacket createDiscoveryPacket(NodeConnector nodeConnector) { - String nodeId = HexEncode.longToHexString((Long) nodeConnector - .getNode().getID()); + String nodeId = HexEncode.longToHexString((Long) nodeConnector.getNode().getID()); // Create LLDP ChassisID TLV byte[] cidValue = LLDPTLV.createChassisIDTLVValue(nodeId); - chassisIdTlv.setType((byte) LLDPTLV.TLVType.ChassisID.getValue()) - .setLength((short) cidValue.length).setValue(cidValue); + chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue()).setLength((short) cidValue.length) + .setValue(cidValue); + + // Create LLDP SystemName TLV + byte[] snValue = LLDPTLV.createSystemNameTLVValue(nodeConnector.getNode().toString()); + systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue()).setLength((short) snValue.length) + .setValue(snValue); // Create LLDP PortID TLV String portId = nodeConnector.getNodeConnectorIDString(); byte[] pidValue = LLDPTLV.createPortIDTLVValue(portId); - portIdTlv.setType((byte) LLDPTLV.TLVType.PortID.getValue()) - .setLength((short) pidValue.length).setValue(pidValue); + portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue()).setLength((short) pidValue.length).setValue(pidValue); // Create LLDP Custom TLV byte[] customValue = LLDPTLV.createCustomTLVValue(nodeConnector.toString()); - customTlv.setType((byte) LLDPTLV.TLVType.Custom.getValue()) - .setLength((short) customValue.length).setValue(customValue); + customTlv.setType(LLDPTLV.TLVType.Custom.getValue()).setLength((short) customValue.length) + .setValue(customValue); // Create LLDP Custom Option list List customList = new ArrayList(); @@ -168,24 +238,22 @@ public class DiscoveryService implements IInventoryShimExternalListener, // Create discovery pkt LLDP discoveryPkt = new LLDP(); - discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl( - ttlTlv).setOptionalTLVList(customList); + discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setSystemNameId(systemNameTlv) + .setOptionalTLVList(customList); RawPacket rawPkt = null; try { // Create ethernet pkt - byte[] sourceMac = getSouceMACFromNodeID(nodeId); + byte[] sourceMac = getSourceMACFromNodeID(nodeId); Ethernet ethPkt = new Ethernet(); - ethPkt.setSourceMACAddress(sourceMac).setDestinationMACAddress( - LLDP.LLDPMulticastMac).setEtherType( - EtherTypes.LLDP.shortValue()).setPayload(discoveryPkt); + ethPkt.setSourceMACAddress(sourceMac).setDestinationMACAddress(LLDP.LLDPMulticastMac) + .setEtherType(EtherTypes.LLDP.shortValue()).setPayload(discoveryPkt); byte[] data = ethPkt.serialize(); rawPkt = new RawPacket(data); rawPkt.setOutgoingNodeConnector(nodeConnector); } catch (ConstructionException cex) { - logger.warn("RawPacket creation caught exception {}", cex - .getMessage()); + logger.warn("RawPacket creation caught exception {}", cex.getMessage()); } catch (Exception e) { logger.error("Failed to serialize the LLDP packet: " + e); } @@ -193,13 +261,17 @@ public class DiscoveryService implements IInventoryShimExternalListener, return rawPkt; } - private void sendDiscoveryPacket(NodeConnector nodeConnector, - RawPacket outPkt) { + private void sendDiscoveryPacket(NodeConnector nodeConnector, RawPacket outPkt) { if (nodeConnector == null) { logger.debug("Can not send discovery packet out since nodeConnector is null"); return; } + if (!connectionOutService.isLocal(nodeConnector.getNode())) { + logger.debug("Discoery packets will not be sent to {} in a non-master controller", nodeConnector.toString()); + return; + } + if (outPkt == null) { logger.debug("Can not send discovery packet out since outPkt is null"); return; @@ -245,43 +317,51 @@ public class DiscoveryService implements IInventoryShimExternalListener, return PacketResult.IGNORED; } - if (((Short) inPkt.getIncomingNodeConnector().getID()) - .equals(NodeConnector.SPECIALNODECONNECTORID)) { + NodeConnector nodeConnector = inPkt.getIncomingNodeConnector(); + if (((Short) nodeConnector.getID()).equals(NodeConnector.SPECIALNODECONNECTORID)) { logger.trace("Ignoring ethernet packet received on special port: " + inPkt.getIncomingNodeConnector().toString()); return PacketResult.IGNORED; } + if (!connectionOutService.isLocal(nodeConnector.getNode())) { + logger.debug("Discoery packets will not be processed from {} in a non-master controller", nodeConnector.toString()); + return PacketResult.IGNORED; + } + Ethernet ethPkt = new Ethernet(); try { ethPkt.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte); } catch (Exception e) { - logger.warn("Failed to decode LLDP packet from " - + inPkt.getIncomingNodeConnector() + ": " + e); + logger.warn("Failed to decode LLDP packet from {}: {}", inPkt.getIncomingNodeConnector(), e); return PacketResult.IGNORED; } + if (ethPkt.getPayload() instanceof LLDP) { NodeConnector dst = inPkt.getIncomingNodeConnector(); - if (!processDiscoveryPacket(dst, ethPkt)) { - /* Spoof the discovery pkt if not generated from us */ - spoofDiscoveryPacket(dst, ethPkt); + if (isEnabled(dst)) { + if (!processDiscoveryPacket(dst, ethPkt)) { + // Snoop the discovery pkt if not generated from us + snoopDiscoveryPacket(dst, ethPkt); + } + return PacketResult.CONSUME; } - return PacketResult.CONSUME; } return PacketResult.IGNORED; } /* - * Spoof incoming discovery frames generated by the production network neighbor switch + * Snoop incoming discovery frames generated by the production network + * neighbor switch */ - private void spoofDiscoveryPacket(NodeConnector dstNodeConnector, - Ethernet ethPkt) { - if (!this.discoverySpoofingEnabled) { + private void snoopDiscoveryPacket(NodeConnector dstNodeConnector, Ethernet ethPkt) { + if (!this.discoverySnoopingEnabled || discoverySnoopingDisableList.contains(dstNodeConnector)) { + logger.trace("Discarded received discovery packet on {} since snooping is turned off", dstNodeConnector); return; } if ((dstNodeConnector == null) || (ethPkt == null)) { - logger.trace("Quit spoofing discovery packet: Null node connector or packet"); + logger.trace("Quit snooping discovery packet: Null node connector or packet"); return; } @@ -290,19 +370,19 @@ public class DiscoveryService implements IInventoryShimExternalListener, try { String nodeId = LLDPTLV.getHexStringValue(lldp.getChassisId().getValue(), lldp.getChassisId().getLength()); String portId = LLDPTLV.getStringValue(lldp.getPortId().getValue(), lldp.getPortId().getLength()); - byte[] systemNameBytes = null; - // get system name if present in the LLDP pkt - for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) { - if (lldptlv.getType() == LLDPTLV.TLVType.SystemName.getValue()) { - systemNameBytes = lldptlv.getValue(); - break; - } - } - String nodeName = (systemNameBytes == null) ? nodeId : new String(systemNameBytes); - Node srcNode = new Node(Node.NodeIDType.PRODUCTION, nodeName); - NodeConnector srcNodeConnector = NodeConnectorCreator - .createNodeConnector(NodeConnector.NodeConnectorIDType.PRODUCTION, - portId, srcNode); + byte[] systemNameBytes = null; + // get system name if present in the LLDP pkt + for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) { + if (lldptlv.getType() == LLDPTLV.TLVType.SystemName.getValue()) { + systemNameBytes = lldptlv.getValue(); + break; + } + } + String nodeName = (systemNameBytes == null) ? nodeId + : new String(systemNameBytes, Charset.defaultCharset()); + Node srcNode = new Node(Node.NodeIDType.PRODUCTION, nodeName); + NodeConnector srcNodeConnector = NodeConnectorCreator.createNodeConnector( + NodeConnector.NodeConnectorIDType.PRODUCTION, portId, srcNode); Edge edge = null; Set props = null; @@ -311,31 +391,33 @@ public class DiscoveryService implements IInventoryShimExternalListener, updateProdEdge(edge, props); } catch (Exception e) { - logger.warn("Caught exception ", e); + if (logger.isDebugEnabled()) { + logger.debug( + "Caught exception while attempting to snoop non controller generated or malformed LLDP frame sent by {} and received on {}: {}", + HexEncode.bytesToHexStringFormat(ethPkt.getSourceMACAddress()), dstNodeConnector, + e.getMessage()); + } } } /* * Handle discovery frames generated by our controller + * * @return true if it's a success */ - private boolean processDiscoveryPacket(NodeConnector dstNodeConnector, - Ethernet ethPkt) { + private boolean processDiscoveryPacket(NodeConnector dstNodeConnector, Ethernet ethPkt) { if ((dstNodeConnector == null) || (ethPkt == null)) { - logger - .trace("Ignoring processing of discovery packet: Null node connector or packet"); + logger.trace("Ignoring processing of discovery packet: Null node connector or packet"); return false; } - logger.trace("Handle discovery packet {} from {}", ethPkt, - dstNodeConnector); + logger.trace("Handle discovery packet {} from {}", ethPkt, dstNodeConnector); LLDP lldp = (LLDP) ethPkt.getPayload(); List optionalTLVList = lldp.getOptionalTLVList(); if (optionalTLVList == null) { - logger.info("The discovery packet with null custom option from {}", - dstNodeConnector); + logger.warn("The discovery packet with null custom option from {}", dstNodeConnector); return false; } @@ -343,26 +425,16 @@ public class DiscoveryService implements IInventoryShimExternalListener, NodeConnector srcNodeConnector = null; for (LLDPTLV lldptlv : lldp.getOptionalTLVList()) { if (lldptlv.getType() == LLDPTLV.TLVType.Custom.getValue()) { - String ncString = LLDPTLV.getCustomString(lldptlv.getValue(), lldptlv.getLength()); - srcNodeConnector = NodeConnector.fromString(ncString); - if (srcNodeConnector != null) { - srcNode = srcNodeConnector.getNode(); - /* Check if it's expected */ - if (isTracked(srcNodeConnector)) { - break; - } else { - srcNode = null; - srcNodeConnector = null; - } + String ncString = LLDPTLV.getCustomString(lldptlv.getValue(), lldptlv.getLength()); + srcNodeConnector = NodeConnector.fromString(ncString); + if (srcNodeConnector != null) { + srcNode = srcNodeConnector.getNode(); } } } if ((srcNode == null) || (srcNodeConnector == null)) { - logger - .trace( - "Received non-controller generated discovery packet from {}", - dstNodeConnector); + logger.trace("Received non-controller generated discovery packet from {}", dstNodeConnector); return false; } @@ -387,12 +459,11 @@ public class DiscoveryService implements IInventoryShimExternalListener, return null; } - if (pluginInInventoryService == null) { + if (inventoryProvider == null) { return null; } - Map> props = pluginInInventoryService - .getNodeConnectorProps(false); + Map> props = inventoryProvider.getNodeConnectorProps(false); if (props == null) { return null; } @@ -406,7 +477,7 @@ public class DiscoveryService implements IInventoryShimExternalListener, return null; } - Property prop = (Property) propMap.get(propName); + Property prop = propMap.get(propName); return prop; } @@ -427,8 +498,7 @@ public class DiscoveryService implements IInventoryShimExternalListener, Config config = (Config) getProp(nodeConnector, Config.ConfigPropName); State state = (State) getProp(nodeConnector, State.StatePropName); - return ((config != null) && (config.getValue() == Config.ADMIN_UP) - && (state != null) && (state.getValue() == State.EDGE_UP)); + return ((config != null) && (config.getValue() == Config.ADMIN_UP) && (state != null) && (state.getValue() == State.EDGE_UP)); } private boolean isTracked(NodeConnector nodeConnector) { @@ -440,11 +510,11 @@ public class DiscoveryService implements IInventoryShimExternalListener, return true; } - if (pendingMap.keySet().contains(nodeConnector)) { + if (holdTime.keySet().contains(nodeConnector)) { return true; } - if (waitingList.contains(nodeConnector)) { + if (stagingList.contains(nodeConnector)) { return true; } @@ -462,6 +532,9 @@ public class DiscoveryService implements IInventoryShimExternalListener, workingSet.add(nodeConnector); removeSet.add(nodeConnector); + + // Put it in the map and start the timer. It may need retry. + elapsedTime.put(nodeConnector, 0); } readyListHi.removeAll(removeSet); @@ -497,14 +570,14 @@ public class DiscoveryService implements IInventoryShimExternalListener, private void addDiscovery(Node node) { Map switches = controller.getSwitches(); - ISwitch sw = switches.get((Long) node.getID()); - List ports = sw.getEnabledPorts(); - if (ports == null) { + ISwitch sw = switches.get(node.getID()); + if (sw == null) { + //switch could be removed by now, stop propagation return; } + List ports = sw.getEnabledPorts(); for (OFPhysicalPort port : ports) { - NodeConnector nodeConnector = NodeConnectorCreator - .createOFNodeConnector(port.getPortNumber(), node); + NodeConnector nodeConnector = NodeConnectorCreator.createOFNodeConnector(port.getPortNumber(), node); if (!readyListHi.contains(nodeConnector)) { readyListHi.add(nodeConnector); } @@ -519,8 +592,15 @@ public class DiscoveryService implements IInventoryShimExternalListener, readyListHi.add(nodeConnector); } - private Set getRemoveSet(Collection c, - Node node) { + private void removeNodeConnector(NodeConnector nodeConnector) { + readyListLo.remove(nodeConnector); + readyListHi.remove(nodeConnector); + stagingList.remove(nodeConnector); + holdTime.remove(nodeConnector); + elapsedTime.remove(nodeConnector); + } + + private Set getRemoveSet(Collection c, Node node) { Set removeSet = new HashSet(); if (c == null) { return removeSet; @@ -536,56 +616,68 @@ public class DiscoveryService implements IInventoryShimExternalListener, private void removeDiscovery(Node node) { Set removeSet; + removeSet = getRemoveSet(edgeMap.keySet(), node); + NodeConnector peerConnector; + Edge edge1, edge2; + for (NodeConnector nodeConnector : removeSet) { + // get the peer for fast removal of the edge in reverse direction + peerConnector = null; + edge1 = edgeMap.get(nodeConnector); + if (edge1 != null) { + edge2 = edgeMap.get(edge1.getTailNodeConnector()); + if ((edge2 != null) && node.equals(edge2.getTailNodeConnector().getNode())) { + peerConnector = edge2.getHeadNodeConnector(); + } + } + + removeEdge(nodeConnector, false); + removeEdge(peerConnector, isEnabled(peerConnector)); + } + + removeSet = getRemoveSet(prodMap.keySet(), node); + for (NodeConnector nodeConnector : removeSet) { + removeProdEdge(nodeConnector); + } + removeSet = getRemoveSet(readyListHi, node); readyListHi.removeAll(removeSet); removeSet = getRemoveSet(readyListLo, node); readyListLo.removeAll(removeSet); - removeSet = getRemoveSet(waitingList, node); - waitingList.removeAll(removeSet); + removeSet = getRemoveSet(stagingList, node); + stagingList.removeAll(removeSet); - removeSet = getRemoveSet(pendingMap.keySet(), node); + removeSet = getRemoveSet(holdTime.keySet(), node); for (NodeConnector nodeConnector : removeSet) { - pendingMap.remove(nodeConnector); + holdTime.remove(nodeConnector); } - removeSet = getRemoveSet(edgeMap.keySet(), node); - for (NodeConnector nodeConnector : removeSet) { - removeEdge(nodeConnector, false); - } - - removeSet = getRemoveSet(prodMap.keySet(), node); + removeSet = getRemoveSet(elapsedTime.keySet(), node); for (NodeConnector nodeConnector : removeSet) { - removeProdEdge(nodeConnector); + elapsedTime.remove(nodeConnector); } } private void removeDiscovery(NodeConnector nodeConnector) { - readyListHi.remove(nodeConnector); - readyListLo.remove(nodeConnector); - waitingList.remove(nodeConnector); - pendingMap.remove(nodeConnector); + removeNodeConnector(nodeConnector); removeEdge(nodeConnector, false); removeProdEdge(nodeConnector); } private void checkTimeout() { Set removeSet = new HashSet(); - Set retrySet = new HashSet(); - int sentCount; - - Set pendingSet = pendingMap.keySet(); - if (pendingSet != null) { - for (NodeConnector nodeConnector : pendingSet) { - sentCount = pendingMap.get(nodeConnector); - pendingMap.put(nodeConnector, ++sentCount); - if (sentCount > getDiscoveryFinalTimeoutInterval()) { + int ticks; + + Set monitorSet = holdTime.keySet(); + if (monitorSet != null) { + for (NodeConnector nodeConnector : monitorSet) { + ticks = holdTime.get(nodeConnector); + holdTime.put(nodeConnector, ++ticks); + if (ticks >= discoveryTimeoutTicks) { // timeout the edge removeSet.add(nodeConnector); logger.trace("Discovery timeout {}", nodeConnector); - } else if (sentCount % discoveryTimeoutTicks == 0) { - retrySet.add(nodeConnector); } } } @@ -594,8 +686,24 @@ public class DiscoveryService implements IInventoryShimExternalListener, removeEdge(nodeConnector); } - for (NodeConnector nodeConnector : retrySet) { - transmitQ.add(nodeConnector); + Set retrySet = new HashSet(); + Set ncSet = elapsedTime.keySet(); + if ((ncSet != null) && (ncSet.size() > 0)) { + for (NodeConnector nodeConnector : ncSet) { + ticks = elapsedTime.get(nodeConnector); + elapsedTime.put(nodeConnector, ++ticks); + if (ticks >= discoveryThresholdTicks) { + retrySet.add(nodeConnector); + } + } + + for (NodeConnector nodeConnector : retrySet) { + // Allow one more retry + elapsedTime.remove(nodeConnector); + if (connectionOutService.isLocal(nodeConnector.getNode())) { + transmitQ.add(nodeConnector); + } + } } } @@ -605,14 +713,14 @@ public class DiscoveryService implements IInventoryShimExternalListener, } Set removeSet = new HashSet(); - int sentCount; + int ticks; Set agingSet = agingMap.keySet(); if (agingSet != null) { for (NodeConnector nodeConnector : agingSet) { - sentCount = agingMap.get(nodeConnector); - agingMap.put(nodeConnector, ++sentCount); - if (sentCount > discoveryAgeoutTicks) { + ticks = agingMap.get(nodeConnector); + agingMap.put(nodeConnector, ++ticks); + if (ticks > discoveryAgeoutTicks) { // age out the edge removeSet.add(nodeConnector); logger.trace("Discovery age out {}", nodeConnector); @@ -628,16 +736,22 @@ public class DiscoveryService implements IInventoryShimExternalListener, private void doDiscovery() { if (++discoveryTimerTickCount <= discoveryBatchPauseTicks) { for (NodeConnector nodeConnector : getWorkingSet()) { - pendingMap.put(nodeConnector, 0); - transmitQ.add(nodeConnector); + if (connectionOutService.isLocal(nodeConnector.getNode())) { + transmitQ.add(nodeConnector); + // Move to staging area after it's served + if (!stagingList.contains(nodeConnector)) { + stagingList.add(nodeConnector); + } + } } } else if (discoveryTimerTickCount >= discoveryBatchRestartTicks) { discoveryTimerTickCount = 0; - for (NodeConnector nodeConnector : waitingList) { - if (!readyListLo.contains(nodeConnector)) + for (NodeConnector nodeConnector : stagingList) { + if (!readyListLo.contains(nodeConnector)) { readyListLo.add(nodeConnector); + } } - waitingList.removeAll(readyListLo); + stagingList.removeAll(readyListLo); } } @@ -646,8 +760,7 @@ public class DiscoveryService implements IInventoryShimExternalListener, return; } - if (++discoveryConsistencyCheckTickCount - % getDiscoveryConsistencyCheckInterval() != 0) { + if (++discoveryConsistencyCheckTickCount % getDiscoveryConsistencyCheckInterval() != 0) { return; } @@ -662,16 +775,14 @@ public class DiscoveryService implements IInventoryShimExternalListener, if (!isEnabled(nodeConnector)) { removeSet.add(nodeConnector); discoveryConsistencyCheckCorrected++; - logger.debug("ConsistencyChecker: remove disabled {}", - nodeConnector); + logger.debug("ConsistencyChecker: remove disabled {}", nodeConnector); continue; } if (!isTracked(nodeConnector)) { - waitingList.add(nodeConnector); + stagingList.add(nodeConnector); discoveryConsistencyCheckCorrected++; - logger.debug("ConsistencyChecker: add back untracked {}", - nodeConnector); + logger.debug("ConsistencyChecker: add back untracked {}", nodeConnector); continue; } } @@ -682,28 +793,25 @@ public class DiscoveryService implements IInventoryShimExternalListener, // remove stale entries removeSet.clear(); - for (NodeConnector nodeConnector : waitingList) { + for (NodeConnector nodeConnector : stagingList) { if (!isEnabled(nodeConnector)) { removeSet.add(nodeConnector); discoveryConsistencyCheckCorrected++; - logger.debug("ConsistencyChecker: remove disabled {}", - nodeConnector); + logger.debug("ConsistencyChecker: remove disabled {}", nodeConnector); } } - waitingList.removeAll(removeSet); + stagingList.removeAll(removeSet); // Get a snapshot of all the existing switches Map switches = this.controller.getSwitches(); for (ISwitch sw : switches.values()) { for (OFPhysicalPort port : sw.getEnabledPorts()) { Node node = NodeCreator.createOFNode(sw.getId()); - NodeConnector nodeConnector = NodeConnectorCreator - .createOFNodeConnector(port.getPortNumber(), node); + NodeConnector nodeConnector = NodeConnectorCreator.createOFNodeConnector(port.getPortNumber(), node); if (!isTracked(nodeConnector)) { - waitingList.add(nodeConnector); + stagingList.add(nodeConnector); discoveryConsistencyCheckCorrected++; - logger.debug("ConsistencyChecker: add back untracked {}", - nodeConnector); + logger.debug("ConsistencyChecker: add back untracked {}", nodeConnector); } } } @@ -715,60 +823,65 @@ public class DiscoveryService implements IInventoryShimExternalListener, } NodeConnector src = edge.getTailNodeConnector(); - if (!src.getType().equals( - NodeConnector.NodeConnectorIDType.PRODUCTION)) { - pendingMap.remove(src); - if (!waitingList.contains(src)) { - waitingList.add(src); - } + NodeConnector dst = edge.getHeadNodeConnector(); + if (!src.getType().equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) { + holdTime.put(dst, 0); } else { - NodeConnector dst = edge.getHeadNodeConnector(); agingMap.put(dst, 0); } + elapsedTime.remove(src); - // notify routeEngine - updateEdge(edge, UpdateType.ADDED, props); + // fast discovery of the edge in reverse direction + if (!edgeMap.containsKey(dst) && !readyListHi.contains(dst) && !elapsedTime.keySet().contains(dst)) { + moveToReadyListHi(dst); + } + + //checking only OF map, since production edge discovery always overwrites any existing edge + UpdateType ut = edgeMap.containsKey(dst) ? UpdateType.CHANGED : UpdateType.ADDED; + // notify + updateEdge(edge, ut, props); logger.trace("Add edge {}", edge); } - /** * Update Production Edge - * - * @param edge The Production Edge - * @param props Properties associated with the edge + * + * @param edge + * The Production Edge + * @param props + * Properties associated with the edge */ private void updateProdEdge(Edge edge, Set props) { - NodeConnector edgePort = edge.getHeadNodeConnector(); - - /* Do not update in case there is an existing OpenFlow link */ - if (edgeMap.get(edgePort) != null) { - logger.trace("Discarded edge {} since there is an existing OF link {}", - edge, edgeMap.get(edgePort)); - return; - } - - /* Look for any existing Production Edge */ - Edge oldEdge = prodMap.get(edgePort); - if (oldEdge == null) { - /* Let's add a new one */ - addEdge(edge, props); - } else if (!edge.equals(oldEdge)) { - /* Remove the old one first */ - removeProdEdge(oldEdge.getHeadNodeConnector()); - /* Then add the new one */ - addEdge(edge, props); - } else { - /* o/w, just reset the aging timer */ + NodeConnector edgePort = edge.getHeadNodeConnector(); + + /* Do not update in case there is an existing OpenFlow link */ + if (edgeMap.get(edgePort) != null) { + logger.trace("Discarded edge {} since there is an existing OF link {}", edge, edgeMap.get(edgePort)); + return; + } + + /* Look for any existing Production Edge */ + Edge oldEdge = prodMap.get(edgePort); + if (oldEdge == null) { + /* Let's add a new one */ + addEdge(edge, props); + } else if (!edge.equals(oldEdge)) { + /* Remove the old one first */ + removeProdEdge(oldEdge.getHeadNodeConnector()); + /* Then add the new one */ + addEdge(edge, props); + } else { + /* o/w, just reset the aging timer */ NodeConnector dst = edge.getHeadNodeConnector(); - agingMap.put(dst, 0); - } + agingMap.put(dst, 0); + } } /** * Remove Production Edge for a given edge port - * - * @param edgePort The OF edge port + * + * @param edgePort + * The OF edge port */ private void removeProdEdge(NodeConnector edgePort) { agingMap.remove(edgePort); @@ -781,8 +894,8 @@ public class DiscoveryService implements IInventoryShimExternalListener, } // notify Topology - if (this.discoveryService != null) { - this.discoveryService.notifyEdge(edge, UpdateType.REMOVED, null); + if (this.discoveryListener != null) { + this.discoveryListener.notifyEdge(edge, UpdateType.REMOVED, null); } logger.trace("Remove edge {}", edge); } @@ -791,18 +904,15 @@ public class DiscoveryService implements IInventoryShimExternalListener, * Remove OpenFlow edge */ private void removeEdge(NodeConnector nodeConnector, boolean stillEnabled) { - pendingMap.remove(nodeConnector); - readyListLo.remove(nodeConnector); - readyListHi.remove(nodeConnector); + if (nodeConnector == null) { + return; + } + + removeNodeConnector(nodeConnector); if (stillEnabled) { // keep discovering - if (!waitingList.contains(nodeConnector)) { - waitingList.add(nodeConnector); - } - } else { - // stop it - waitingList.remove(nodeConnector); + stagingList.add(nodeConnector); } Edge edge = null; @@ -813,8 +923,8 @@ public class DiscoveryService implements IInventoryShimExternalListener, } // notify Topology - if (this.discoveryService != null) { - this.discoveryService.notifyEdge(edge, UpdateType.REMOVED, null); + if (this.discoveryListener != null) { + this.discoveryListener.notifyEdge(edge, UpdateType.REMOVED, null); } logger.trace("Remove {}", nodeConnector); } @@ -824,20 +934,19 @@ public class DiscoveryService implements IInventoryShimExternalListener, } private void updateEdge(Edge edge, UpdateType type, Set props) { - if (discoveryService == null) { + if (discoveryListener == null) { return; } - this.discoveryService.notifyEdge(edge, type, props); - NodeConnector src = edge.getTailNodeConnector(), dst = edge - .getHeadNodeConnector(); - if (!src.getType().equals( - NodeConnector.NodeConnectorIDType.PRODUCTION)) { + this.discoveryListener.notifyEdge(edge, type, props); + + NodeConnector src = edge.getTailNodeConnector(), dst = edge.getHeadNodeConnector(); + if (!src.getType().equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) { if (type == UpdateType.ADDED) { - edgeMap.put(src, edge); + edgeMap.put(dst, edge); } else { - edgeMap.remove(src); + edgeMap.remove(dst); } } else { /* @@ -851,101 +960,121 @@ public class DiscoveryService implements IInventoryShimExternalListener, } } - private void moreToReadyListHi(NodeConnector nodeConnector) { + private void moveToReadyListHi(NodeConnector nodeConnector) { if (readyListLo.contains(nodeConnector)) { readyListLo.remove(nodeConnector); - readyListHi.add(nodeConnector); - } else if (waitingList.contains(nodeConnector)) { - waitingList.remove(nodeConnector); - readyListHi.add(nodeConnector); + } else if (stagingList.contains(nodeConnector)) { + stagingList.remove(nodeConnector); } + readyListHi.add(nodeConnector); } private void registerWithOSGIConsole() { - BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()) - .getBundleContext(); - bundleContext.registerService(CommandProvider.class.getName(), this, - null); + BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); + bundleContext.registerService(CommandProvider.class.getName(), this, null); } private int getDiscoveryConsistencyCheckInterval() { return discoveryConsistencyCheckMultiple * discoveryBatchRestartTicks; } - private int getDiscoveryFinalTimeoutInterval() { - return (discoveryRetry + 1) * discoveryTimeoutTicks; - } - @Override public String getHelp() { StringBuffer help = new StringBuffer(); help.append("---Topology Discovery---\n"); - help.append("\t prlh - Print readyListHi entries\n"); - help.append("\t prll - Print readyListLo entries\n"); - help.append("\t pwl - Print waitingList entries\n"); - help.append("\t ppl - Print pendingList entries\n"); - help.append("\t ptick - Print tick time in msec\n"); - help.append("\t pcc - Print CC info\n"); - help.append("\t psize - Print sizes of all the lists\n"); - help.append("\t ptm - Print timeout info\n"); - help.append("\t ecc - Enable CC\n"); - help.append("\t dcc - Disable CC\n"); - help.append("\t scc [multiple] - Set/show CC multiple and interval\n"); - help.append("\t sports [ports] - Set/show max ports per batch\n"); - help.append("\t spause [ticks] - Set/show pause period\n"); - help.append("\t sdi [ticks] - Set/show discovery interval in ticks\n"); - help.append("\t stm [ticks] - Set/show per timeout ticks\n"); - help.append("\t sretry [count] - Set/show num of retries\n"); - help.append("\t addsw - Add a switch\n"); - help.append("\t remsw - Remove a switch\n"); - help.append("\t page - Print aging info\n"); - help.append("\t sage - Set/Show aging time limit\n"); - help.append("\t eage - Enable aging\n"); - help.append("\t dage - Disable aging\n"); - help.append("\t pthrot - Print throttling\n"); - help.append("\t ethrot - Enable throttling\n"); - help.append("\t dthrot - Disable throttling\n"); + help.append("\t prlh - Print readyListHi entries\n"); + help.append("\t prll - Print readyListLo entries\n"); + help.append("\t psl - Print stagingList entries\n"); + help.append("\t pht - Print hold time\n"); + help.append("\t pet - Print elapsed time\n"); + help.append("\t ptick - Print tick time in msec\n"); + help.append("\t pcc - Print CC info\n"); + help.append("\t psize - Print sizes of all the lists\n"); + help.append("\t ptm - Print timeout info\n"); + help.append("\t ecc - Enable CC\n"); + help.append("\t dcc - Disable CC\n"); + help.append("\t scc [multiple] - Set/show CC multiple and interval\n"); + help.append("\t sports [ports] - Set/show max ports per batch\n"); + help.append("\t spause [ticks] - Set/show pause period\n"); + help.append("\t sdi [ticks] - Set/show discovery interval in ticks\n"); + help.append("\t addsw - Add a switch\n"); + help.append("\t remsw - Remove a switch\n"); + help.append("\t page - Print aging info\n"); + help.append("\t sage - Set/Show aging time limit\n"); + help.append("\t eage - Enable aging\n"); + help.append("\t dage - Disable aging\n"); + help.append("\t pthrot - Print throttling\n"); + help.append("\t ethrot - Enable throttling\n"); + help.append("\t dthrot - Disable throttling\n"); + help.append("\t psnp - Print LLDP snooping\n"); + help.append("\t esnp - Enable LLDP snooping\n"); + help.append("\t dsnp - Disable LLDP snooping\n"); return help.toString(); } + private List sortList(Collection ncs) { + List ncStrArray = new ArrayList(); + for (NodeConnector nc : ncs) { + ncStrArray.add(nc.toString()); + } + Collections.sort(ncStrArray); + + List sortedNodeConnectors = new ArrayList(); + for (String ncStr : ncStrArray) { + sortedNodeConnectors.add(NodeConnector.fromString(ncStr)); + } + + return sortedNodeConnectors; + } + public void _prlh(CommandInterpreter ci) { - ci.println("ReadyListHi\n"); - for (NodeConnector nodeConnector : readyListHi) { + ci.println("readyListHi\n"); + for (NodeConnector nodeConnector : sortList(readyListHi)) { if (nodeConnector == null) { continue; } ci.println(nodeConnector); } + ci.println("Total number of Node Connectors: " + readyListHi.size()); } public void _prll(CommandInterpreter ci) { - ci.println("ReadyListLo\n"); - for (NodeConnector nodeConnector : readyListLo) { + ci.println("readyListLo\n"); + for (NodeConnector nodeConnector : sortList(readyListLo)) { if (nodeConnector == null) { continue; } ci.println(nodeConnector); } + ci.println("Total number of Node Connectors: " + readyListLo.size()); } - public void _pwl(CommandInterpreter ci) { - ci.println("WaitingList\n"); - for (NodeConnector nodeConnector : waitingList) { + public void _psl(CommandInterpreter ci) { + ci.println("stagingList\n"); + for (NodeConnector nodeConnector : sortList(stagingList)) { if (nodeConnector == null) { continue; } ci.println(nodeConnector); } + ci.println("Total number of Node Connectors: " + stagingList.size()); } - public void _ppl(CommandInterpreter ci) { - ci.println("PendingList\n"); - for (NodeConnector nodeConnector : pendingMap.keySet()) { - if (nodeConnector == null) { - continue; - } - ci.println(nodeConnector); + public void _pht(CommandInterpreter ci) { + ci.println(" NodeConnector Last rx LLDP (sec)"); + for (ConcurrentMap.Entry entry: holdTime.entrySet()) { + ci.println(entry.getKey() + "\t\t" + entry.getValue() * (discoveryTimerTick / 1000)); } + ci.println("\nSize: " + holdTime.size() + "\tTimeout: " + discoveryTimeoutTicks * (discoveryTimerTick / 1000) + + " sec"); + } + + public void _pet(CommandInterpreter ci) { + ci.println(" NodeConnector Elapsed Time (sec)"); + for (ConcurrentMap.Entry entry: elapsedTime.entrySet()) { + ci.println(entry.getKey() + "\t\t" + entry.getValue() * (discoveryTimerTick / 1000)); + } + ci.println("\nSize: " + elapsedTime.size() + "\tThreshold: " + DiscoveryPeriod.THRESHOLD.getTime() + " sec"); } public void _ptick(CommandInterpreter ci) { @@ -960,24 +1089,19 @@ public class DiscoveryService implements IInventoryShimExternalListener, } ci.println("Interval " + getDiscoveryConsistencyCheckInterval()); ci.println("Multiple " + discoveryConsistencyCheckMultiple); - ci.println("Number of times called " - + discoveryConsistencyCheckCallingTimes); + ci.println("Number of times called " + discoveryConsistencyCheckCallingTimes); ci.println("Corrected count " + discoveryConsistencyCheckCorrected); } public void _ptm(CommandInterpreter ci) { - ci.println("Final timeout ticks " + getDiscoveryFinalTimeoutInterval()); - ci.println("Per timeout ticks " + discoveryTimeoutTicks); - ci.println("Retry after initial timeout " + discoveryRetry); + ci.println("Timeout " + discoveryTimeoutTicks + " ticks, " + discoveryTimerTick / 1000 + " sec per tick."); } public void _psize(CommandInterpreter ci) { - ci.println("readyListLo size " + readyListLo.size() + "\n" - + "readyListHi size " + readyListHi.size() + "\n" - + "waitingList size " + waitingList.size() + "\n" - + "pendingMap size " + pendingMap.size() + "\n" - + "edgeMap size " + edgeMap.size() + "\n" + "prodMap size " - + prodMap.size() + "\n" + "agingMap size " + agingMap.size()); + ci.println("readyListLo size " + readyListLo.size() + "\n" + "readyListHi size " + readyListHi.size() + "\n" + + "stagingList size " + stagingList.size() + "\n" + "holdTime size " + holdTime.size() + "\n" + + "edgeMap size " + edgeMap.size() + "\n" + "prodMap size " + prodMap.size() + "\n" + "agingMap size " + + agingMap.size() + "\n" + "elapsedTime size " + elapsedTime.size()); } public void _page(CommandInterpreter ci) { @@ -1000,7 +1124,7 @@ public class DiscoveryService implements IInventoryShimExternalListener, } } ci.println("\n"); - ci.println(" NodeConnector Edge "); + ci.println(" NodeConnector Edge "); Set keySet = prodMap.keySet(); if (keySet == null) { return; @@ -1014,8 +1138,7 @@ public class DiscoveryService implements IInventoryShimExternalListener, public void _sage(CommandInterpreter ci) { String val = ci.nextArgument(); if (val == null) { - ci.println("Please enter aging time limit. Current value " - + this.discoveryAgeoutTicks); + ci.println("Please enter aging time limit. Current value " + this.discoveryAgeoutTicks); return; } try { @@ -1041,10 +1164,8 @@ public class DiscoveryService implements IInventoryShimExternalListener, public void _scc(CommandInterpreter ci) { String val = ci.nextArgument(); if (val == null) { - ci.println("Please enter CC multiple. Current multiple " - + discoveryConsistencyCheckMultiple + " (interval " - + getDiscoveryConsistencyCheckInterval() - + ") calling times " + ci.println("Please enter CC multiple. Current multiple " + discoveryConsistencyCheckMultiple + + " (interval " + getDiscoveryConsistencyCheckInterval() + ") calling times " + discoveryConsistencyCheckCallingTimes); return; } @@ -1068,40 +1189,72 @@ public class DiscoveryService implements IInventoryShimExternalListener, return; } - public void _pspf(CommandInterpreter ci) { - if (this.discoverySpoofingEnabled) { - ci.println("Discovery spoofing is enabled"); + public void _psnp(CommandInterpreter ci) { + if (this.discoverySnoopingEnabled) { + ci.println("Discovery snooping is globally enabled"); } else { - ci.println("Discovery spoofing is disabled"); + ci.println("Discovery snooping is globally disabled"); + } + + ci.println("\nDiscovery snooping is locally disabled on these ports"); + for (NodeConnector nodeConnector : discoverySnoopingDisableList) { + ci.println(nodeConnector); } return; } - public void _espf(CommandInterpreter ci) { - this.discoverySpoofingEnabled = true; - ci.println("Discovery spoofing is enabled"); + public void _esnp(CommandInterpreter ci) { + String val = ci.nextArgument(); + + if (val == null) { + ci.println("Usage: esnp "); + } else if (val.equalsIgnoreCase("all")) { + this.discoverySnoopingEnabled = true; + ci.println("Discovery snooping is globally enabled"); + } else { + NodeConnector nodeConnector = NodeConnector.fromString(val); + if (nodeConnector != null) { + discoverySnoopingDisableList.remove(nodeConnector); + ci.println("Discovery snooping is locally enabled on port " + nodeConnector); + } else { + ci.println("Entered invalid NodeConnector " + val); + } + } return; } - public void _dspf(CommandInterpreter ci) { - this.discoverySpoofingEnabled = false; - ci.println("Discovery spoofing is disabled"); + public void _dsnp(CommandInterpreter ci) { + String val = ci.nextArgument(); + + if (val == null) { + ci.println("Usage: dsnp "); + } else if (val.equalsIgnoreCase("all")) { + this.discoverySnoopingEnabled = false; + ci.println("Discovery snooping is globally disabled"); + } else { + NodeConnector nodeConnector = NodeConnector.fromString(val); + if (nodeConnector != null) { + discoverySnoopingDisableList.add(nodeConnector); + ci.println("Discovery snooping is locally disabled on port " + nodeConnector); + } else { + ci.println("Entered invalid NodeConnector " + val); + } + } return; } public void _spause(CommandInterpreter ci) { String val = ci.nextArgument(); - String out = "Please enter pause period less than " - + discoveryBatchRestartTicks + ". Current pause period is " - + discoveryBatchPausePeriod + " pause tick is " - + discoveryBatchPauseTicks + "."; + String out = "Please enter pause period less than " + discoveryBatchRestartTicks + ". Current pause period is " + + discoveryBatchPausePeriod + " ticks, pause at " + discoveryBatchPauseTicks + " ticks, " + + discoveryTimerTick / 1000 + " sec per tick."; if (val != null) { try { int pause = Integer.parseInt(val); if (pause < discoveryBatchRestartTicks) { - discoveryBatchPausePeriod = pause; - discoveryBatchPauseTicks = discoveryBatchRestartTicks - discoveryBatchPausePeriod; + discoveryBatchPausePeriod = pause; + discoveryBatchPauseTicks = getDiscoveryPauseInterval(); return; } } catch (Exception e) { @@ -1113,20 +1266,27 @@ public class DiscoveryService implements IInventoryShimExternalListener, public void _sdi(CommandInterpreter ci) { String val = ci.nextArgument(); - String out = "Please enter discovery interval greater than " - + discoveryBatchPausePeriod + ". Current value is " - + discoveryBatchRestartTicks + "."; + String out = "Please enter discovery interval in ticks. Current value is " + discoveryBatchRestartTicks + " ticks, " + + discoveryTimerTick / 1000 + " sec per tick."; if (val != null) { - try { - int restart = Integer.parseInt(val); - if (restart > discoveryBatchPausePeriod) { - discoveryBatchRestartTicks = restart; - discoveryBatchPauseTicks = discoveryBatchRestartTicks - discoveryBatchPausePeriod; - return; - } - } catch (Exception e) { - } + try { + int ticks; + Set monitorSet = holdTime.keySet(); + if (monitorSet != null) { + for (NodeConnector nodeConnector : monitorSet) { + holdTime.put(nodeConnector, 0); + } + } + + ticks = Integer.parseInt(val); + DiscoveryPeriod.INTERVAL.setTick(ticks); + discoveryBatchRestartTicks = getDiscoveryInterval(); + discoveryBatchPauseTicks = getDiscoveryPauseInterval(); + discoveryTimeoutTicks = getDiscoveryTimeout(); + return; + } catch (Exception e) { + } } ci.println(out); } @@ -1134,8 +1294,7 @@ public class DiscoveryService implements IInventoryShimExternalListener, public void _sports(CommandInterpreter ci) { String val = ci.nextArgument(); if (val == null) { - ci.println("Please enter max ports per batch. Current value is " - + discoveryBatchMaxPorts); + ci.println("Please enter max ports per batch. Current value is " + discoveryBatchMaxPorts); return; } try { @@ -1146,40 +1305,6 @@ public class DiscoveryService implements IInventoryShimExternalListener, return; } - public void _sretry(CommandInterpreter ci) { - String val = ci.nextArgument(); - if (val == null) { - ci.println("Please enter number of retries. Current value is " - + discoveryRetry); - return; - } - try { - discoveryRetry = Integer.parseInt(val); - } catch (Exception e) { - ci.println("Please enter a valid number"); - } - return; - } - - public void _stm(CommandInterpreter ci) { - String val = ci.nextArgument(); - String out = "Please enter timeout tick value less than " - + discoveryBatchRestartTicks + ". Current value is " - + discoveryTimeoutTicks; - if (val != null) { - try { - int timeout = Integer.parseInt(val); - if (timeout < discoveryBatchRestartTicks) { - discoveryTimeoutTicks = timeout; - return; - } - } catch (Exception e) { - } - } - - ci.println(out); - } - public void _addsw(CommandInterpreter ci) { String val = ci.nextArgument(); Long sid; @@ -1241,8 +1366,7 @@ public class DiscoveryService implements IInventoryShimExternalListener, } @Override - public void updateNodeConnector(NodeConnector nodeConnector, - UpdateType type, Set props) { + public void updateNodeConnector(NodeConnector nodeConnector, UpdateType type, Set props) { Config config = null; State state = null; boolean enabled = false; @@ -1254,8 +1378,7 @@ public class DiscoveryService implements IInventoryShimExternalListener, state = (State) prop; } } - enabled = ((config != null) && (config.getValue() == Config.ADMIN_UP) - && (state != null) && (state.getValue() == State.EDGE_UP)); + enabled = ((config != null) && (config.getValue() == Config.ADMIN_UP) && (state != null) && (state.getValue() == State.EDGE_UP)); switch (type) { case ADDED: @@ -1285,22 +1408,21 @@ public class DiscoveryService implements IInventoryShimExternalListener, } public void addNode(Node node, Set props) { - if (node == null) + if (node == null) { return; + } addDiscovery(node); } public void removeNode(Node node) { - if (node == null) + if (node == null) { return; + } removeDiscovery(node); } - public void updateNode(Node node, Set props) { - } - void setController(IController s) { this.controller = s; } @@ -1311,12 +1433,12 @@ public class DiscoveryService implements IInventoryShimExternalListener, } } - public void setPluginInInventoryService(IPluginInInventoryService service) { - this.pluginInInventoryService = service; + public void setInventoryProvider(IInventoryProvider service) { + this.inventoryProvider = service; } - public void unsetPluginInInventoryService(IPluginInInventoryService service) { - this.pluginInInventoryService = null; + public void unsetInventoryProvider(IInventoryProvider service) { + this.inventoryProvider = null; } public void setIDataPacketMux(IDataPacketMux service) { @@ -1329,30 +1451,43 @@ public class DiscoveryService implements IInventoryShimExternalListener, } } - void setDiscoveryService(IDiscoveryService s) { - this.discoveryService = s; + void setDiscoveryListener(IDiscoveryListener s) { + this.discoveryListener = s; + } + + void unsetDiscoveryListener(IDiscoveryListener s) { + if (this.discoveryListener == s) { + this.discoveryListener = null; + } + } + + void setIPluginOutConnectionService(IPluginOutConnectionService s) { + connectionOutService = s; } - void unsetDiscoveryService(IDiscoveryService s) { - if (this.discoveryService == s) { - this.discoveryService = null; + void unsetIPluginOutConnectionService(IPluginOutConnectionService s) { + if (connectionOutService == s) { + connectionOutService = null; } } private void initDiscoveryPacket() { // Create LLDP ChassisID TLV chassisIdTlv = new LLDPTLV(); - chassisIdTlv.setType((byte) LLDPTLV.TLVType.ChassisID.getValue()); + chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue()); + + // Create LLDP SystemName TLV + systemNameTlv = new LLDPTLV(); + systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue()); // Create LLDP PortID TLV portIdTlv = new LLDPTLV(); - portIdTlv.setType((byte) LLDPTLV.TLVType.PortID.getValue()); + portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue()); // Create LLDP TTL TLV - byte[] ttl = new byte[] { (byte) 120 }; + byte[] ttl = new byte[] { (byte) 0, (byte) 120 }; ttlTlv = new LLDPTLV(); - ttlTlv.setType((byte) LLDPTLV.TLVType.TTL.getValue()).setLength( - (short) ttl.length).setValue(ttl); + ttlTlv.setType(LLDPTLV.TLVType.TTL.getValue()).setLength((short) ttl.length).setValue(ttl); customTlv = new LLDPTLV(); } @@ -1369,11 +1504,21 @@ public class DiscoveryService implements IInventoryShimExternalListener, readyListHi = new CopyOnWriteArrayList(); readyListLo = new CopyOnWriteArrayList(); - waitingList = new CopyOnWriteArrayList(); - pendingMap = new ConcurrentHashMap(); + stagingList = new CopyOnWriteArrayList(); + holdTime = new ConcurrentHashMap(); + elapsedTime = new ConcurrentHashMap(); edgeMap = new ConcurrentHashMap(); agingMap = new ConcurrentHashMap(); prodMap = new ConcurrentHashMap(); + discoverySnoopingDisableList = new CopyOnWriteArrayList(); + + discoveryBatchRestartTicks = getDiscoveryInterval(); + discoveryBatchPauseTicks = getDiscoveryPauseInterval(); + discoveryTimeoutTicks = getDiscoveryTimeout(); + discoveryThresholdTicks = getDiscoveryThreshold(); + discoveryAgeoutTicks = getDiscoveryAgeout(); + discoveryConsistencyCheckTickCount = discoveryBatchPauseTicks; + discoveryBatchMaxPorts = getDiscoveryBatchMaxPorts(); discoveryTimer = new Timer("DiscoveryService"); discoveryTimerTask = new DiscoveryTimerTask(); @@ -1395,8 +1540,8 @@ public class DiscoveryService implements IInventoryShimExternalListener, transmitQ = null; readyListHi = null; readyListLo = null; - waitingList = null; - pendingMap = null; + stagingList = null; + holdTime = null; edgeMap = null; agingMap = null; prodMap = null; @@ -1411,14 +1556,12 @@ public class DiscoveryService implements IInventoryShimExternalListener, * */ void start() { - discoveryTimer.schedule(discoveryTimerTask, discoveryTimerTick, - discoveryTimerTick); + discoveryTimer.schedule(discoveryTimerTask, discoveryTimerTick, discoveryTimerTick); transmitThread.start(); } /** - * Function called after registering the - * service in OSGi service registry. + * Function called after registering the service in OSGi service registry. */ void started() { /* get a snapshot of all the existing switches */ @@ -1438,21 +1581,19 @@ public class DiscoveryService implements IInventoryShimExternalListener, } @Override - public void tagUpdated(String containerName, Node n, short oldTag, - short newTag, UpdateType t) { + public void tagUpdated(String containerName, Node n, short oldTag, short newTag, UpdateType t) { } @Override - public void containerFlowUpdated(String containerName, - ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) { + public void containerFlowUpdated(String containerName, ContainerFlow previousFlow, ContainerFlow currentFlow, + UpdateType t) { } @Override - public void nodeConnectorUpdated(String containerName, NodeConnector p, - UpdateType t) { + public void nodeConnectorUpdated(String containerName, NodeConnector p, UpdateType t) { switch (t) { case ADDED: - moreToReadyListHi(p); + moveToReadyListHi(p); break; default: break; @@ -1463,16 +1604,112 @@ public class DiscoveryService implements IInventoryShimExternalListener, public void containerModeUpdated(UpdateType t) { // do nothing } - - private byte[] getSouceMACFromNodeID(String nodeId) { + + private byte[] getSourceMACFromNodeID(String nodeId) { byte[] cid = HexEncode.bytesFromHexString(nodeId); byte[] sourceMac = new byte[6]; int pos = cid.length - sourceMac.length; if (pos >= 0) { - System.arraycopy(cid, pos, sourceMac, 0, sourceMac.length); + System.arraycopy(cid, pos, sourceMac, 0, sourceMac.length); } - + return sourceMac; } + + private int getDiscoveryTicks(DiscoveryPeriod dp, String val) { + if (dp == null) { + return 0; + } + + if (val != null) { + try { + dp.setTime(Integer.parseInt(val)); + } catch (Exception e) { + } + } + + return dp.getTick(); + } + + /** + * This method returns the interval which determines how often the discovery + * packets will be sent. + * + * @return The discovery interval in ticks + */ + private int getDiscoveryInterval() { + String intvl = System.getProperty("of.discoveryInterval"); + return getDiscoveryTicks(DiscoveryPeriod.INTERVAL, intvl); + } + + /** + * This method returns the timeout value in receiving subsequent discovery packets on a port. + * + * @return The discovery timeout in ticks + */ + private int getDiscoveryTimeout() { + String val = System.getProperty("of.discoveryTimeoutMultiple"); + int multiple = 2; + + if (val != null) { + try { + multiple = Integer.parseInt(val); + } catch (Exception e) { + } + } + return getDiscoveryInterval() * multiple + 3; + } + + /** + * This method returns the user configurable threshold value + * + * @return The discovery threshold value in ticks + */ + private int getDiscoveryThreshold() { + String val = System.getProperty("of.discoveryThreshold"); + return getDiscoveryTicks(DiscoveryPeriod.THRESHOLD, val); + } + + /** + * This method returns the discovery entry aging time in ticks. + * + * @return The aging time in ticks + */ + private int getDiscoveryAgeout() { + return getDiscoveryTicks(DiscoveryPeriod.AGEOUT, null); + } + + /** + * This method returns the pause interval + * + * @return The pause interval in ticks + */ + private int getDiscoveryPauseInterval() { + if (discoveryBatchRestartTicks > discoveryBatchPausePeriod) { + return discoveryBatchRestartTicks - discoveryBatchPausePeriod; + } else { + return discoveryBatchRestartTicks - 1; + } + } + + /** + * This method returns the user configurable maximum number of ports handled + * in one discovery batch. + * + * @return The maximum number of ports + */ + private int getDiscoveryBatchMaxPorts() { + String val = System.getProperty("of.discoveryBatchMaxPorts"); + int ports = 512; + + if (val != null) { + try { + ports = Integer.parseInt(val); + } catch (Exception e) { + } + } + return ports; + } + }