From e647cb87a2c2c10a86d7ec8897637ce08a392415 Mon Sep 17 00:00:00 2001 From: Anton Frolov Date: Sat, 4 Oct 2014 19:02:12 +0400 Subject: [PATCH] BUG-2242: LLDP speaker as separate application. * Remove LLDPSpeaker and all related classes and methods from openflowplugin * Create separate LLDPSpeaker application * Replace usage of Timer with ScheduledExecutorService which use monotonic timer for delays instead of system time. * Decomposed LLDPSpeaker into several classes to improve unit testabilty * added lldp app to base distro Change-Id: I997c74203af7461840c1c711355120b415995c06 Signed-off-by: Anton Frolov Signed-off-by: Michal Rehak --- applications/lldp-speaker/pom.xml | 105 ++++++++ .../applications/lldpspeaker/LLDPSpeaker.java | 134 ++++++++++ .../applications/lldpspeaker/LLDPUtil.java | 103 ++++++++ .../NodeConnectorEventsObserver.java | 38 +++ ...NodeConnectorInventoryEventTranslator.java | 113 +++++++++ .../speaker/rev141023/LLDPSpeakerModule.java | 49 ++++ .../rev141023/LLDPSpeakerModuleFactory.java | 13 + .../resources/initial/71-lldp-speaker.xml | 33 +++ .../src/main/yang/lldp-speaker.yang | 42 ++++ .../lldpspeaker/LLDPSpeakerTest.java | 149 +++++++++++ ...ConnectorInventoryEventTranslatorTest.java | 238 ++++++++++++++++++ .../applications/lldpspeaker/TestUtils.java | 57 +++++ applications/pom.xml | 5 +- distribution/base/pom.xml | 6 + features/src/main/resources/features.xml | 3 + .../openflow/md/it/OFPaxOptionsAssistant.java | 1 - openflowplugin/pom.xml | 4 - .../openflow/md/core/MDController.java | 5 - .../md/core/sal/SalRegistrationManager.java | 3 - .../openflow/md/lldp/LLDPSpeaker.java | 192 -------------- .../md/lldp/LLDPSpeakerPopListener.java | 45 ---- .../md/lldp/LLDPSpeakerPopListenerTest.java | 91 ------- 22 files changed, 1086 insertions(+), 343 deletions(-) create mode 100644 applications/lldp-speaker/pom.xml create mode 100644 applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/LLDPSpeaker.java create mode 100644 applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/LLDPUtil.java create mode 100644 applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/NodeConnectorEventsObserver.java create mode 100644 applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/NodeConnectorInventoryEventTranslator.java create mode 100644 applications/lldp-speaker/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/applications/lldp/speaker/rev141023/LLDPSpeakerModule.java create mode 100644 applications/lldp-speaker/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/applications/lldp/speaker/rev141023/LLDPSpeakerModuleFactory.java create mode 100644 applications/lldp-speaker/src/main/resources/initial/71-lldp-speaker.xml create mode 100644 applications/lldp-speaker/src/main/yang/lldp-speaker.yang create mode 100644 applications/lldp-speaker/src/test/java/org/opendaylight/openflowplugin/applications/lldpspeaker/LLDPSpeakerTest.java create mode 100644 applications/lldp-speaker/src/test/java/org/opendaylight/openflowplugin/applications/lldpspeaker/NodeConnectorInventoryEventTranslatorTest.java create mode 100644 applications/lldp-speaker/src/test/java/org/opendaylight/openflowplugin/applications/lldpspeaker/TestUtils.java delete mode 100644 openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPSpeaker.java delete mode 100644 openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPSpeakerPopListener.java delete mode 100644 openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPSpeakerPopListenerTest.java diff --git a/applications/lldp-speaker/pom.xml b/applications/lldp-speaker/pom.xml new file mode 100644 index 0000000000..78f8b9002e --- /dev/null +++ b/applications/lldp-speaker/pom.xml @@ -0,0 +1,105 @@ + + + 4.0.0 + + org.opendaylight.openflowplugin + applications + 0.1.0-SNAPSHOT + + org.opendaylight.openflowplugin.applications + lldp-speaker + bundle + + + org.opendaylight.openflowplugin + openflowplugin-api + + + org.opendaylight.controller + sal-binding-api + + + org.opendaylight.controller + sal-binding-broker-impl + + + org.opendaylight.controller.model + model-inventory + + + org.opendaylight.controller.model + model-flow-service + + + org.opendaylight.controller + config-api + + + org.opendaylight.controller + liblldp + + + + + org.mockito + mockito-all + test + + + junit + junit + test + + + + + + + org.jacoco + jacoco-maven-plugin + + + + ${project.basedir}/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/**/*.java + + + + + + + org.opendaylight.yangtools + yang-maven-plugin + + + + org.apache.felix + maven-bundle-plugin + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-artifacts + + attach-artifact + + package + + + + ${project.build.directory}/classes/initial/71-lldp-speaker.xml + xml + config + + + + + + + + + diff --git a/applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/LLDPSpeaker.java b/applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/LLDPSpeaker.java new file mode 100644 index 0000000000..93af6869a4 --- /dev/null +++ b/applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/LLDPSpeaker.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2014 Pacnet and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowplugin.applications.lldpspeaker; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.*; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Objects of this class send LLDP frames over all flow-capable ports that can + * be discovered through inventory. + */ +public class LLDPSpeaker implements AutoCloseable, NodeConnectorEventsObserver, Runnable { + private static final Logger LOG = LoggerFactory.getLogger(LLDPSpeaker.class); + private static final long LLDP_FLOOD_PERIOD = 5; + + private final PacketProcessingService packetProcessingService; + private final ScheduledExecutorService scheduledExecutorService; + private final Map, TransmitPacketInput> nodeConnectorMap = + new ConcurrentHashMap<>(); + private final ScheduledFuture scheduledSpeakerTask; + + public LLDPSpeaker(PacketProcessingService packetProcessingService) { + this(packetProcessingService, Executors.newSingleThreadScheduledExecutor()); + } + + public LLDPSpeaker(PacketProcessingService packetProcessingService, + ScheduledExecutorService scheduledExecutorService) { + this.scheduledExecutorService = scheduledExecutorService; + scheduledSpeakerTask = this.scheduledExecutorService.scheduleAtFixedRate( + this, LLDP_FLOOD_PERIOD, LLDP_FLOOD_PERIOD, TimeUnit.SECONDS); + this.packetProcessingService = packetProcessingService; + LOG.info("LLDPSpeaker started, it will send LLDP frames each {} seconds", LLDP_FLOOD_PERIOD); + } + + /** + * Closes this resource, relinquishing any underlying resources. + */ + @Override + public void close() { + nodeConnectorMap.clear(); + scheduledExecutorService.shutdown(); + scheduledSpeakerTask.cancel(true); + LOG.trace("LLDPSpeaker stopped sending LLDP frames."); + } + + /** + * Send LLDPDU frames to all known openflow switch ports. + */ + @Override + public void run() { + LOG.debug("Sending LLDP frames to {} ports...", nodeConnectorMap.keySet().size()); + + for (InstanceIdentifier nodeConnectorInstanceId : nodeConnectorMap.keySet()) { + NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(nodeConnectorInstanceId).getId(); + LOG.trace("Sending LLDP through port {}", nodeConnectorId.getValue()); + packetProcessingService.transmitPacket(nodeConnectorMap.get(nodeConnectorInstanceId)); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void nodeConnectorAdded(InstanceIdentifier nodeConnectorInstanceId, + FlowCapableNodeConnector flowConnector) { + NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(nodeConnectorInstanceId).getId(); + + // nodeConnectorAdded can be called even if we already sending LLDP frames to + // port, so first we check if we actually need to perform any action + if (nodeConnectorMap.containsKey(nodeConnectorInstanceId)) { + LOG.trace("Port {} already in LLDPSpeaker.nodeConnectorMap, no need for additional processing", + nodeConnectorId.getValue()); + return; + } + + // Prepare to build LLDP payload + InstanceIdentifier nodeInstanceId = nodeConnectorInstanceId.firstIdentifierOf(Node.class); + NodeId nodeId = InstanceIdentifier.keyOf(nodeInstanceId).getId(); + MacAddress srcMacAddress = flowConnector.getHardwareAddress(); + Long outputPortNo = flowConnector.getPortNumber().getUint32(); + + // No need to send LLDP frames on local ports + if (outputPortNo == null) { + LOG.trace("Port {} is local, not sending LLDP frames through it", + nodeConnectorId.getValue()); + return; + } + + // Generate packet with destination switch and port + TransmitPacketInput packet = new TransmitPacketInputBuilder() + .setEgress(new NodeConnectorRef(nodeConnectorInstanceId)) + .setNode(new NodeRef(nodeInstanceId)) + .setPayload(LLDPUtil.buildLldpFrame(nodeId, nodeConnectorId, srcMacAddress, outputPortNo)) + .build(); + + // Save packet to node connector id -> packet map to transmit it every 5 seconds + nodeConnectorMap.put(nodeConnectorInstanceId, packet); + LOG.trace("Port {} added to LLDPSpeaker.nodeConnectorMap", nodeConnectorId.getValue()); + + // Transmit packet for first time immediately + packetProcessingService.transmitPacket(packet); + } + + /** + * {@inheritDoc} + */ + @Override + public void nodeConnectorRemoved(InstanceIdentifier nodeConnectorInstanceId) { + nodeConnectorMap.remove(nodeConnectorInstanceId); + NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(nodeConnectorInstanceId).getId(); + LOG.trace("Port {} removed from LLDPSpeaker.nodeConnectorMap", nodeConnectorId.getValue()); + } +} diff --git a/applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/LLDPUtil.java b/applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/LLDPUtil.java new file mode 100644 index 0000000000..07a5d527d7 --- /dev/null +++ b/applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/LLDPUtil.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2014 Pacnet and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowplugin.applications.lldpspeaker; + +import java.math.BigInteger; +import java.util.Collections; +import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.opendaylight.controller.liblldp.EtherTypes; +import org.opendaylight.controller.liblldp.Ethernet; +import org.opendaylight.controller.liblldp.HexEncode; +import org.opendaylight.controller.liblldp.LLDP; +import org.opendaylight.controller.liblldp.LLDPTLV; +import org.opendaylight.controller.liblldp.PacketException; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class for dealing with LLDP packets. + */ +public final class LLDPUtil { + private static final Logger LOG = LoggerFactory.getLogger(LLDPUtil.class); + private static final String OF_URI_PREFIX = "openflow:"; + + static byte[] buildLldpFrame(NodeId nodeId, NodeConnectorId nodeConnectorId, MacAddress src, Long outPortNo) { + // Create LLDP TTL TLV + byte[] ttl = new byte[] { (byte) 0x13, (byte) 0x37 }; + LLDPTLV ttlTlv = new LLDPTLV(); + ttlTlv.setType(LLDPTLV.TLVType.TTL.getValue()).setLength((short) ttl.length).setValue(ttl); + + // Create LLDP ChassisID TLV + BigInteger dataPathId = dataPathIdFromNodeId(nodeId); + byte[] cidValue = LLDPTLV.createChassisIDTLVValue( + colonize(bigIntegerToPaddedHex(dataPathId))); + LLDPTLV chassisIdTlv = new LLDPTLV(); + chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue()); + chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue()).setLength((short) cidValue.length) + .setValue(cidValue); + + // Create LLDP SystemName TLV + byte[] snValue = LLDPTLV.createSystemNameTLVValue(nodeId.getValue()); + LLDPTLV systemNameTlv = new LLDPTLV(); + systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue()); + systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue()).setLength((short) snValue.length) + .setValue(snValue); + + // Create LLDP PortID TL + String hexString = Long.toHexString(outPortNo); + byte[] pidValue = LLDPTLV.createPortIDTLVValue(hexString); + LLDPTLV portIdTlv = new LLDPTLV(); + portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue()).setLength((short) pidValue.length).setValue(pidValue); + portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue()); + + // Create LLDP Custom TLV + byte[] customValue = LLDPTLV.createCustomTLVValue(nodeConnectorId.getValue()); + LLDPTLV customTlv = new LLDPTLV(); + customTlv.setType(LLDPTLV.TLVType.Custom.getValue()).setLength((short) customValue.length) + .setValue(customValue); + + // Create LLDP Custom Option list + List customList = Collections.singletonList(customTlv); + + // Create discovery pkt + LLDP discoveryPkt = new LLDP(); + discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setSystemNameId(systemNameTlv) + .setOptionalTLVList(customList); + + // Create ethernet pkt + byte[] sourceMac = HexEncode.bytesFromHexString(src.getValue()); + Ethernet ethPkt = new Ethernet(); + ethPkt.setSourceMACAddress(sourceMac).setDestinationMACAddress(LLDP.LLDPMulticastMac) + .setEtherType(EtherTypes.LLDP.shortValue()).setPayload(discoveryPkt); + + try { + return ethPkt.serialize(); + } catch (PacketException e) { + LOG.error("Error creating LLDP packet",e); + } + return null; + } + + private static String colonize(String orig) { + return orig.replaceAll("(?<=..)(..)", ":$1"); + } + + private static BigInteger dataPathIdFromNodeId(NodeId nodeId) { + String dpids = nodeId.getValue().replace(OF_URI_PREFIX, ""); + return new BigInteger(dpids); + } + + private static String bigIntegerToPaddedHex(BigInteger dataPathId) { + return StringUtils.leftPad(dataPathId.toString(16), 16, "0"); + } +} diff --git a/applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/NodeConnectorEventsObserver.java b/applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/NodeConnectorEventsObserver.java new file mode 100644 index 0000000000..490cf6ad28 --- /dev/null +++ b/applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/NodeConnectorEventsObserver.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014 Pacnet and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowplugin.applications.lldpspeaker; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * NodeConnectorEventsObserver can be added to NodeConnectorInventoryEventTranslator to receive events + * when node connector added or removed. + */ +public interface NodeConnectorEventsObserver { + /** + * This method is called when new node connector is added to inventory or when existing + * node connector changed it's status to UP. This method can be called multiple times for + * the same creation event. + * + * @param nodeConnectorInstanceId Object that uniquely identify added node connector + * @param flowConnector object containing almost all of details about node connector + */ + public void nodeConnectorAdded(InstanceIdentifier nodeConnectorInstanceId, + FlowCapableNodeConnector flowConnector); + + /** + * This method is called when some node connector is removed from inventory or when existing + * node connector changed it's status to DOWN. This method can be called multiple times for + * the same removal event. + * @param nodeConnectorInstanceId Object that uniquely identify added node connector + */ + public void nodeConnectorRemoved(InstanceIdentifier nodeConnectorInstanceId); +} diff --git a/applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/NodeConnectorInventoryEventTranslator.java b/applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/NodeConnectorInventoryEventTranslator.java new file mode 100644 index 0000000000..2f32718c0e --- /dev/null +++ b/applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/NodeConnectorInventoryEventTranslator.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2014 Pacnet and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowplugin.applications.lldpspeaker; + +import com.google.common.collect.ImmutableSet; +import java.util.Map; +import java.util.Set; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * NodeConnectorInventoryEventTranslator is listening for changes in inventory operational DOM tree + * and update LLDPSpeaker and topology. + */ +public class NodeConnectorInventoryEventTranslator implements DataChangeListener, AutoCloseable { + private static final Logger LOG = LoggerFactory.getLogger(NodeConnectorInventoryEventTranslator.class); + + private final ListenerRegistration dataChangeListenerRegistration; + private final Set observers; + + public NodeConnectorInventoryEventTranslator(DataBroker dataBroker, NodeConnectorEventsObserver... observers) { + this.observers = ImmutableSet.copyOf(observers); + dataChangeListenerRegistration = dataBroker.registerDataChangeListener( + LogicalDatastoreType.OPERATIONAL, + InstanceIdentifier.builder(Nodes.class) + .child(Node.class) + .child(NodeConnector.class) + .augmentation(FlowCapableNodeConnector.class) + .toInstance(), + this, AsyncDataBroker.DataChangeScope.BASE); + } + + @Override + public void close() { + dataChangeListenerRegistration.close(); + } + + @Override + public void onDataChanged(AsyncDataChangeEvent, DataObject> change) { + LOG.trace("Node connectors in inventory changed: {} created, {} updated, {} removed", + change.getCreatedData().size(), change.getUpdatedData().size(), change.getRemovedPaths().size()); + + // Iterate over created node connectors + for (Map.Entry, DataObject> entry : change.getCreatedData().entrySet()) { + InstanceIdentifier nodeConnectorInstanceId = + entry.getKey().firstIdentifierOf(NodeConnector.class); + + FlowCapableNodeConnector flowConnector = (FlowCapableNodeConnector) entry.getValue(); + if (!isPortDown(flowConnector)) { + notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowConnector); + } + } + + // Iterate over updated node connectors (port down state may change) + for (Map.Entry, DataObject> entry : change.getUpdatedData().entrySet()) { + InstanceIdentifier nodeConnectorInstanceId = + entry.getKey().firstIdentifierOf(NodeConnector.class); + FlowCapableNodeConnector flowConnector = (FlowCapableNodeConnector) entry.getValue(); + if (isPortDown(flowConnector)) { + notifyNodeConnectorDisappeared(nodeConnectorInstanceId); + } else { + notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowConnector); + } + } + + // Iterate over removed node connectors + for (InstanceIdentifier removed : change.getRemovedPaths()) { + InstanceIdentifier nodeConnectorInstanceId = removed.firstIdentifierOf(NodeConnector.class); + notifyNodeConnectorDisappeared(nodeConnectorInstanceId); + } + } + + private static boolean isPortDown(FlowCapableNodeConnector flowCapableNodeConnector) { + PortState portState = flowCapableNodeConnector.getState(); + PortConfig portConfig = flowCapableNodeConnector.getConfiguration(); + return portState != null && portState.isLinkDown() || + portConfig != null && portConfig.isPORTDOWN(); + } + + private void notifyNodeConnectorAppeared(InstanceIdentifier nodeConnectorInstanceId, + FlowCapableNodeConnector flowConnector) { + for (NodeConnectorEventsObserver observer : observers) { + observer.nodeConnectorAdded(nodeConnectorInstanceId, flowConnector); + } + } + + private void notifyNodeConnectorDisappeared(InstanceIdentifier nodeConnectorInstanceId) { + for (NodeConnectorEventsObserver observer : observers) { + observer.nodeConnectorRemoved(nodeConnectorInstanceId); + } + } +} diff --git a/applications/lldp-speaker/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/applications/lldp/speaker/rev141023/LLDPSpeakerModule.java b/applications/lldp-speaker/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/applications/lldp/speaker/rev141023/LLDPSpeakerModule.java new file mode 100644 index 0000000000..ed135c83fe --- /dev/null +++ b/applications/lldp-speaker/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/applications/lldp/speaker/rev141023/LLDPSpeakerModule.java @@ -0,0 +1,49 @@ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.applications.lldp.speaker.rev141023; + +import org.opendaylight.controller.config.api.DependencyResolver; +import org.opendaylight.controller.config.api.ModuleIdentifier; +import org.opendaylight.openflowplugin.applications.lldpspeaker.LLDPSpeaker; +import org.opendaylight.openflowplugin.applications.lldpspeaker.NodeConnectorInventoryEventTranslator; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LLDPSpeakerModule extends AbstractLLDPSpeakerModule { + private static final Logger LOG = LoggerFactory.getLogger(LLDPSpeakerModule.class); + + public LLDPSpeakerModule(ModuleIdentifier identifier, DependencyResolver dependencyResolver) { + super(identifier, dependencyResolver); + } + + public LLDPSpeakerModule(ModuleIdentifier identifier, DependencyResolver dependencyResolver, + LLDPSpeakerModule oldModule, AutoCloseable oldInstance) { + super(identifier, dependencyResolver, oldModule, oldInstance); + } + + @Override + public void customValidation() { + // add custom validation form module attributes here. + } + + @Override + public AutoCloseable createInstance() { + LOG.trace("Creating LLDP speaker."); + + PacketProcessingService packetProcessingService = + getRpcRegistryDependency().getRpcService(PacketProcessingService.class); + + final LLDPSpeaker lldpSpeaker = new LLDPSpeaker(packetProcessingService); + final NodeConnectorInventoryEventTranslator eventTranslator = + new NodeConnectorInventoryEventTranslator(getDataBrokerDependency(), lldpSpeaker); + + return new AutoCloseable() { + @Override + public void close() { + LOG.trace("Closing LLDP speaker."); + eventTranslator.close(); + lldpSpeaker.close(); + } + }; + } + +} diff --git a/applications/lldp-speaker/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/applications/lldp/speaker/rev141023/LLDPSpeakerModuleFactory.java b/applications/lldp-speaker/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/applications/lldp/speaker/rev141023/LLDPSpeakerModuleFactory.java new file mode 100644 index 0000000000..a09e921c40 --- /dev/null +++ b/applications/lldp-speaker/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/applications/lldp/speaker/rev141023/LLDPSpeakerModuleFactory.java @@ -0,0 +1,13 @@ +/* +* Generated file +* +* Generated from: yang module name: lldp-speaker yang module local name: lldp-speaker +* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator +* Generated at: Thu Oct 23 10:01:14 MSK 2014 +* +* Do not modify this file unless it is present under src/main directory +*/ +package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.applications.lldp.speaker.rev141023; +public class LLDPSpeakerModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.applications.lldp.speaker.rev141023.AbstractLLDPSpeakerModuleFactory { + +} diff --git a/applications/lldp-speaker/src/main/resources/initial/71-lldp-speaker.xml b/applications/lldp-speaker/src/main/resources/initial/71-lldp-speaker.xml new file mode 100644 index 0000000000..dbbe8e1853 --- /dev/null +++ b/applications/lldp-speaker/src/main/resources/initial/71-lldp-speaker.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + prefix:lldp-speaker + lldp-speaker + + binding:binding-async-data-broker + binding-data-broker + + + binding:binding-rpc-registry + binding-rpc-broker + + + + + + + \ No newline at end of file diff --git a/applications/lldp-speaker/src/main/yang/lldp-speaker.yang b/applications/lldp-speaker/src/main/yang/lldp-speaker.yang new file mode 100644 index 0000000000..471d4a4bd3 --- /dev/null +++ b/applications/lldp-speaker/src/main/yang/lldp-speaker.yang @@ -0,0 +1,42 @@ +module lldp-speaker { + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:openflow:applications:lldp-speaker"; + prefix "lldp-speaker"; + import config {prefix config; revision-date 2013-04-05;} + import opendaylight-md-sal-binding { prefix mdsal; revision-date 2013-10-28;} + + description + "Application that send LLDPDU frames to all Openflow switch ports."; + + revision "2014-10-23" { + description + "Initial revision"; + } + + identity lldp-speaker { + base "config:module-type"; + config:java-name-prefix LLDPSpeaker; + } + + augment "/config:modules/config:module/config:configuration" { + case lldp-speaker { + when "/config:modules/config:module/config:type = 'lldp-speaker'"; + container rpc-registry { + uses config:service-ref { + refine type { + mandatory true; + config:required-identity mdsal:binding-rpc-registry; + } + } + } + container data-broker { + uses config:service-ref { + refine type { + mandatory false; + config:required-identity mdsal:binding-async-data-broker; + } + } + } + } + } +} diff --git a/applications/lldp-speaker/src/test/java/org/opendaylight/openflowplugin/applications/lldpspeaker/LLDPSpeakerTest.java b/applications/lldp-speaker/src/test/java/org/opendaylight/openflowplugin/applications/lldpspeaker/LLDPSpeakerTest.java new file mode 100644 index 0000000000..b872d16148 --- /dev/null +++ b/applications/lldp-speaker/src/test/java/org/opendaylight/openflowplugin/applications/lldpspeaker/LLDPSpeakerTest.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2014 Pacnet and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowplugin.applications.lldpspeaker; + +import static org.mockito.Mockito.*; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import org.junit.*; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.CommonPort; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Tests for @{LLDPSpeaker} class. + */ +@RunWith(MockitoJUnitRunner.class) +public class LLDPSpeakerTest { + static InstanceIdentifier id; + static FlowCapableNodeConnector fcnc; + static TransmitPacketInput packet; + + static { + MacAddress mac = new MacAddress("01:23:45:67:89:AB"); + id = TestUtils.createNodeConnectorId("openflow:1", "openflow:1:1"); + fcnc = TestUtils.createFlowCapableNodeConnector(mac, 1L).build(); + byte[] lldpFrame = LLDPUtil.buildLldpFrame( + new NodeId("openflow:1"), new NodeConnectorId("openflow:1:1"), mac, 1L); + packet = new TransmitPacketInputBuilder() + .setEgress(new NodeConnectorRef(id)) + .setNode(new NodeRef(id.firstIdentifierOf(Node.class))) + .setPayload(lldpFrame).build(); + } + + @Mock PacketProcessingService packetProcessingService; + @Mock ScheduledExecutorService scheduledExecutorService; + @Mock ScheduledFuture scheduledSpeakerTask; + LLDPSpeaker lldpSpeaker; + + @Before + @SuppressWarnings("unchecked") + public void setUp() { + when(scheduledExecutorService.scheduleAtFixedRate( + any(Runnable.class), anyLong(), anyLong(), any(TimeUnit.class))) + .thenReturn(scheduledSpeakerTask); + lldpSpeaker = new LLDPSpeaker(packetProcessingService, scheduledExecutorService); + } + + /** + * Test that LLDP frame is transmitted after port appeared in inventory and + * periodically after that. + */ + @Test + public void testNodeConnectorAdd() { + // Add node connector - LLDP packet should be transmitted through packetProcessingService + lldpSpeaker.nodeConnectorAdded(id, fcnc); + + // Execute one iteration of periodic task - LLDP packet should be transmitted second time + lldpSpeaker.run(); + + // Check packet transmission + verify(packetProcessingService, times(2)).transmitPacket(packet); + verifyNoMoreInteractions(packetProcessingService); + } + + /** + * Test that LLDP frame stop to periodically transmit after port disappeared + * from inventory. + */ + @Test + public void testNodeConnectorRemoval() { + // Prepare for test - add node connector first + lldpSpeaker.nodeConnectorAdded(id, fcnc); + + // Trigger removal of packet + lldpSpeaker.nodeConnectorRemoved(id); + + // Run one iteration of LLDP flood + lldpSpeaker.run(); + + // Verify that LLDP frame sent only once (by nodeConnectorAdded), + // e.g. no flood after removal + verify(packetProcessingService, times(1)).transmitPacket(packet); + verifyNoMoreInteractions(packetProcessingService); + } + + /** + * Test that when @{LLDPSpeaker#nodeConnectorAdded} is called multiple times + * with same arguments, only the first one have effect. + */ + @Test + public void testMultipleSameNodeConnectorAddEvents() { + // Add node connector - LLDP packet should be transmitted through packetProcessingService + for (int i = 0; i < 10; i++) { + lldpSpeaker.nodeConnectorAdded(id, fcnc); + } + + // Check packet transmission + verify(packetProcessingService, times(1)).transmitPacket(packet); + verifyNoMoreInteractions(packetProcessingService); + } + + /** + * Test that lldpSpeaker cancels periodic LLDP flood task and stops + * @{ScheduledExecutorService}. + * @throws Exception + */ + @Test + public void testCleanup() throws Exception { + lldpSpeaker.close(); + verify(scheduledSpeakerTask, times(1)).cancel(true); + verify(scheduledExecutorService, times(1)).shutdown(); + } + + /** + * Test that checks if LLDPSpeaker working fine with local ports. + */ + @Test + public void testLocalNodeConnectorCreation() { + // Call nodeConnectorAdded with local port + FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector() + .setPortNumber(new CommonPort.PortNumber("LOCAL")) + .build(); + lldpSpeaker.nodeConnectorAdded(id, fcnc); + + // Verify that nothing happened for local port + verify(packetProcessingService, never()).transmitPacket(any(TransmitPacketInput.class)); + } +} diff --git a/applications/lldp-speaker/src/test/java/org/opendaylight/openflowplugin/applications/lldpspeaker/NodeConnectorInventoryEventTranslatorTest.java b/applications/lldp-speaker/src/test/java/org/opendaylight/openflowplugin/applications/lldpspeaker/NodeConnectorInventoryEventTranslatorTest.java new file mode 100644 index 0000000000..a526922043 --- /dev/null +++ b/applications/lldp-speaker/src/test/java/org/opendaylight/openflowplugin/applications/lldpspeaker/NodeConnectorInventoryEventTranslatorTest.java @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2014 Pacnet and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowplugin.applications.lldpspeaker; + +import static org.mockito.Mockito.*; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.junit.*; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + + +/** + * Tests for @{NodeConnectorInventoryEventTranslator} class. + */ +@RunWith(MockitoJUnitRunner.class) +public class NodeConnectorInventoryEventTranslatorTest { + static InstanceIdentifier id = TestUtils.createNodeConnectorId("openflow:1", "openflow:1:1"); + static FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector().build(); + + @Mock DataBroker dataBroker; + @Mock ListenerRegistration dataChangeListenerRegistration; + @Mock NodeConnectorEventsObserver eventsObserver; + @Mock NodeConnectorEventsObserver eventsObserver2; + + MockDataChangedEvent dataChangedEvent = new MockDataChangedEvent(); + NodeConnectorInventoryEventTranslator translator; + + @Before + public void setUp() { + when(dataBroker.registerDataChangeListener( + any(LogicalDatastoreType.class), + any(InstanceIdentifier.class), + any(DataChangeListener.class), + any(AsyncDataBroker.DataChangeScope.class))) + .thenReturn(dataChangeListenerRegistration); + translator = new NodeConnectorInventoryEventTranslator(dataBroker, eventsObserver, eventsObserver2); + } + + /** + * Test that checks if @{NodeConnectorEventsObserver#nodeConnectorAdded} is called + * for each FlowCapableNodeConnector item that @{AsyncDataChangeEvent#getCreatedData} return. + */ + @Test + public void testNodeConnectorCreation() { + // Setup dataChangedEvent to mock new port creation in inventory + dataChangedEvent.created.put(id, fcnc); + + // Invoke NodeConnectorInventoryEventTranslator and check result + translator.onDataChanged(dataChangedEvent); + verify(eventsObserver).nodeConnectorAdded(id, fcnc); + } + + /** + * Test that checks that nothing is called when port appeared in inventory in link down state. + */ + @Test + public void testNodeConnectorCreationLinkDown() { + FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector(true, false).build(); + + // Setup dataChangedEvent to mock new port creation in inventory + dataChangedEvent.created.put(id, fcnc); + + // Invoke NodeConnectorInventoryEventTranslator and check result + translator.onDataChanged(dataChangedEvent); + verifyZeroInteractions(eventsObserver); + } + + /** + * Test that checks that nothing is called when port appeared in inventory in admin down state. + */ + @Test + public void testNodeConnectorCreationAdminDown() { + FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector(false, true).build(); + + // Setup dataChangedEvent to mock new port creation in inventory + dataChangedEvent.created.put(id, fcnc); + + // Invoke NodeConnectorInventoryEventTranslator and check result + translator.onDataChanged(dataChangedEvent); + verifyZeroInteractions(eventsObserver); + } + + /** + * Test that checks if @{NodeConnectorEventsObserver#nodeConnectorRemoved} is called + * for each FlowCapableNodeConnector item inside @{AsyncDataChangeEvent#getUpdatedData} + * that have link down state. + */ + @Test + public void testNodeConnectorUpdateToLinkDown() { + FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector(true, false).build(); + + // Setup dataChangedEvent to mock link down + dataChangedEvent.updated.put(id, fcnc); + + // Invoke NodeConnectorInventoryEventTranslator and check result + translator.onDataChanged(dataChangedEvent); + verify(eventsObserver).nodeConnectorRemoved(id); + } + + /** + * Test that checks if @{NodeConnectorEventsObserver#nodeConnectorRemoved} is called + * for each FlowCapableNodeConnector item inside @{AsyncDataChangeEvent#getUpdatedData} + * that have administrative down state. + */ + @Test + public void testNodeConnectorUpdateToAdminDown() { + FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector(false, true).build(); + + // Setup dataChangedEvent to mock link down and administrative port down + dataChangedEvent.updated.put(id, fcnc); + + // Invoke NodeConnectorInventoryEventTranslator and check result + translator.onDataChanged(dataChangedEvent); + verify(eventsObserver).nodeConnectorRemoved(id); + } + + /** + * Test that checks if @{NodeConnectorEventsObserver#nodeConnectorAdded} is called + * for each FlowCapableNodeConnector item inside @{AsyncDataChangeEvent#getUpdatedData} + * that have administrative up and link up state. + */ + @Test + public void testNodeConnectorUpdateToUp() { + // Setup dataChangedEvent to mock link up and administrative port up + dataChangedEvent.updated.put(id, fcnc); + + // Invoke NodeConnectorInventoryEventTranslator and check result + translator.onDataChanged(dataChangedEvent); + verify(eventsObserver).nodeConnectorAdded(id, fcnc); + } + + /** + * Test that checks if @{NodeConnectorEventsObserver#nodeConnectorRemoved} is called + * for each FlowCapableNodeConnector path that @{AsyncDataChangeEvent#getRemovedPaths} return. + */ + @Test + public void testNodeConnectorRemoval() { + // Setup dataChangedEvent to mock node connector removal + dataChangedEvent.removed.add(id); + + // Invoke NodeConnectorInventoryEventTranslator and check result + translator.onDataChanged(dataChangedEvent); + verify(eventsObserver).nodeConnectorRemoved(id); + } + + /** + * Test that checks if @{NodeConnectorEventsObserver#nodeConnectorAdded} and + * @{NodeConnectorEventsObserver#nodeConnectorRemoved} are called for each + * observer when multiple observers are registered for notifications. + */ + @Test + public void testMultipleObserversNotified() throws Exception { + // Create prerequisites + InstanceIdentifier id2 = TestUtils.createNodeConnectorId("openflow:1", "openflow:1:2"); + + // Setup dataChangedEvent to mock port creation and removal + dataChangedEvent.created.put(id, fcnc); + dataChangedEvent.removed.add(id2); + + // Invoke onDataChanged and check that both observers notified + translator.onDataChanged(dataChangedEvent); + verify(eventsObserver).nodeConnectorAdded(id, fcnc); + verify(eventsObserver).nodeConnectorRemoved(id2); + verify(eventsObserver2).nodeConnectorAdded(id, fcnc); + verify(eventsObserver2).nodeConnectorRemoved(id2); + } + + /** + * Test that @{ListenerRegistration} is closed when ${NodeConnectorInventoryEventTranslator#close} + * method is called. + * @throws Exception + */ + @Test + public void testCleanup() throws Exception { + // Trigger cleanup + translator.close(); + + // Verify that ListenerRegistration to DOM events + verify(dataChangeListenerRegistration).close(); + } + + static class MockDataChangedEvent implements AsyncDataChangeEvent, DataObject> { + Map,DataObject> created = new HashMap<>(); + Map,DataObject> updated = new HashMap<>(); + Set> removed = new HashSet<>(); + + @Override + public Map, DataObject> getCreatedData() { + return created; + } + + @Override + public Map, DataObject> getUpdatedData() { + return updated; + } + + @Override + public Set> getRemovedPaths() { + return removed; + } + + @Override + public Map, DataObject> getOriginalData() { + throw new UnsupportedOperationException("Not implemented by mock"); + } + + @Override + public DataObject getOriginalSubtree() { + throw new UnsupportedOperationException("Not implemented by mock"); + } + + @Override + public DataObject getUpdatedSubtree() { + throw new UnsupportedOperationException("Not implemented by mock"); + } + } +} diff --git a/applications/lldp-speaker/src/test/java/org/opendaylight/openflowplugin/applications/lldpspeaker/TestUtils.java b/applications/lldp-speaker/src/test/java/org/opendaylight/openflowplugin/applications/lldpspeaker/TestUtils.java new file mode 100644 index 0000000000..7445f3fe1e --- /dev/null +++ b/applications/lldp-speaker/src/test/java/org/opendaylight/openflowplugin/applications/lldpspeaker/TestUtils.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014 Pacnet and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.openflowplugin.applications.lldpspeaker; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.CommonPort; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.StateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Helper methods that are used by multiple tests. + */ +public class TestUtils { + static InstanceIdentifier createNodeConnectorId(String nodeKey, String nodeConnectorKey) { + return InstanceIdentifier.builder(Nodes.class) + .child(Node.class, new NodeKey(new NodeId(nodeKey))) + .child(NodeConnector.class, new NodeConnectorKey(new NodeConnectorId(nodeConnectorKey))) + .build(); + } + + static FlowCapableNodeConnectorBuilder createFlowCapableNodeConnector() { + return createFlowCapableNodeConnector(false, false); + } + + static FlowCapableNodeConnectorBuilder createFlowCapableNodeConnector(boolean linkDown, boolean adminDown) { + return createFlowCapableNodeConnector(linkDown, adminDown, new MacAddress("13:37:BA:AD:F0:0D"), 1L); + } + + static FlowCapableNodeConnectorBuilder createFlowCapableNodeConnector(MacAddress mac, long port) { + return createFlowCapableNodeConnector(false, false, mac, port); + } + + static FlowCapableNodeConnectorBuilder createFlowCapableNodeConnector(boolean linkDown, boolean adminDown, + MacAddress mac, long port) { + return new FlowCapableNodeConnectorBuilder() + .setHardwareAddress(mac) + .setPortNumber(new CommonPort.PortNumber(port)) + .setState(new StateBuilder().setLinkDown(linkDown).build()) + .setConfiguration(new PortConfig(false, false, false, adminDown)); + } + +} diff --git a/applications/pom.xml b/applications/pom.xml index 709b06a2be..066bd03c03 100644 --- a/applications/pom.xml +++ b/applications/pom.xml @@ -101,6 +101,7 @@ table-miss-enforcer of-switch-config-pusher - + lldp-speaker + - \ No newline at end of file + diff --git a/distribution/base/pom.xml b/distribution/base/pom.xml index 3824dda769..e39c542a09 100644 --- a/distribution/base/pom.xml +++ b/distribution/base/pom.xml @@ -126,6 +126,12 @@ see https://git.opendaylight.org/gerrit/#/c/390/ table-miss-enforcer ${project.version} + + org.opendaylight.openflowplugin.applications + lldp-speaker + ${project.version} + + diff --git a/features/src/main/resources/features.xml b/features/src/main/resources/features.xml index 4a3cd5c89c..3832a09ff5 100644 --- a/features/src/main/resources/features.xml +++ b/features/src/main/resources/features.xml @@ -54,5 +54,8 @@ mvn:org.opendaylight.openflowplugin.applications/of-switch-config-pusher/${project.version} mvn:org.opendaylight.openflowplugin.applications/of-switch-config-pusher/${project.version}/xml/config + + mvn:org.opendaylight.openflowplugin.applications/lldp-speaker/${project.version} + mvn:org.opendaylight.openflowplugin.applications/lldp-speaker/${project.version}/xml/config diff --git a/openflowplugin-it/src/test/java/org/opendaylight/openflowplugin/openflow/md/it/OFPaxOptionsAssistant.java b/openflowplugin-it/src/test/java/org/opendaylight/openflowplugin/openflow/md/it/OFPaxOptionsAssistant.java index 391512a249..ed62919663 100644 --- a/openflowplugin-it/src/test/java/org/opendaylight/openflowplugin/openflow/md/it/OFPaxOptionsAssistant.java +++ b/openflowplugin-it/src/test/java/org/opendaylight/openflowplugin/openflow/md/it/OFPaxOptionsAssistant.java @@ -101,7 +101,6 @@ public abstract class OFPaxOptionsAssistant { return new DefaultCompositeOption( // mavenBundle("org.apache.felix", "org.apache.felix.dependencymanager").versionAsInProject(), // mavenBundle(CONTROLLER, "sal").versionAsInProject(), - mavenBundle(CONTROLLER, "liblldp").versionAsInProject(), mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject()); } diff --git a/openflowplugin/pom.xml b/openflowplugin/pom.xml index 325de46b1f..4a77e4683c 100644 --- a/openflowplugin/pom.xml +++ b/openflowplugin/pom.xml @@ -99,10 +99,6 @@ openflowplugin-extension-api ${project.version} - - org.opendaylight.controller - liblldp - org.opendaylight.controller.model model-flow-base diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/MDController.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/MDController.java index bd41e3d191..73bec50864 100644 --- a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/MDController.java +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/MDController.java @@ -45,7 +45,6 @@ import org.opendaylight.openflowplugin.openflow.md.core.translator.NotificationP import org.opendaylight.openflowplugin.openflow.md.core.translator.PacketInTranslator; import org.opendaylight.openflowplugin.openflow.md.core.translator.PacketInV10Translator; import org.opendaylight.openflowplugin.openflow.md.core.translator.PortStatusMessageToNodeConnectorUpdatedTranslator; -import org.opendaylight.openflowplugin.openflow.md.lldp.LLDPSpeakerPopListener; import org.opendaylight.openflowplugin.api.openflow.md.queue.PopListener; import org.opendaylight.openflowplugin.openflow.md.util.OpenflowPortsUtil; import org.opendaylight.openflowplugin.api.statistics.MessageSpy; @@ -213,10 +212,6 @@ public class MDController implements IMDController, AutoCloseable { //Notification registration for queue-statistics addMessagePopListener(QueueStatisticsUpdate.class, notificationPopListener); - //Notification for LLDPSpeaker - LLDPSpeakerPopListener lldpPopListener = new LLDPSpeakerPopListener(); - addMessagePopListener(NodeConnectorUpdated.class,lldpPopListener); - // Push the updated Listeners to Session Manager which will be then picked up by ConnectionConductor eventually OFSessionUtil.getSessionManager().setTranslatorMapping(messageTranslators); OFSessionUtil.getSessionManager().setPopListenerMapping(popListeners); diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/SalRegistrationManager.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/SalRegistrationManager.java index ee5e8e951c..ec62918fc5 100644 --- a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/SalRegistrationManager.java +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/SalRegistrationManager.java @@ -23,7 +23,6 @@ import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionConte import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionListener; import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionManager; import org.opendaylight.openflowplugin.api.openflow.md.core.session.SwitchSessionKeyOF; -import org.opendaylight.openflowplugin.openflow.md.lldp.LLDPSpeaker; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address; @@ -99,7 +98,6 @@ public class SalRegistrationManager implements SessionListener, AutoCloseable { NodeRef nodeRef = new NodeRef(identifier); NodeId nodeId = nodeIdFromDatapathId(datapathId); ModelDrivenSwitchImpl ofSwitch = new ModelDrivenSwitchImpl(nodeId, identifier, context); - LLDPSpeaker.getInstance().addModelDrivenSwitch(identifier, ofSwitch); CompositeObjectRegistration registration = ofSwitch.register(providerContext); context.setProviderRegistration(registration); @@ -118,7 +116,6 @@ public class SalRegistrationManager implements SessionListener, AutoCloseable { InstanceIdentifier identifier = identifierFromDatapathId(datapathId); NodeRef nodeRef = new NodeRef(identifier); NodeRemoved nodeRemoved = nodeRemoved(nodeRef); - LLDPSpeaker.getInstance().removeModelDrivenSwitch(identifier); if (context.isValid()) { CompositeObjectRegistration registration = context.getProviderRegistration(); registration.close(); diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPSpeaker.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPSpeaker.java deleted file mode 100644 index 2f97e13513..0000000000 --- a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPSpeaker.java +++ /dev/null @@ -1,192 +0,0 @@ -/** - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.openflowplugin.openflow.md.lldp; - -import java.math.BigInteger; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.ConcurrentHashMap; -import org.opendaylight.controller.liblldp.EtherTypes; -import org.opendaylight.controller.liblldp.Ethernet; -import org.opendaylight.controller.liblldp.HexEncode; -import org.opendaylight.controller.liblldp.LLDP; -import org.opendaylight.controller.liblldp.LLDPTLV; -import org.opendaylight.controller.liblldp.PacketException; -import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion; -import org.opendaylight.openflowplugin.api.openflow.md.ModelDrivenSwitch; -import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -public class LLDPSpeaker { - private static Logger LOG = LoggerFactory.getLogger(LLDPSpeaker.class); - - private final Map, TransmitPacketInput> nodeConnectorMap = new ConcurrentHashMap, TransmitPacketInput>(); - private final Map, ModelDrivenSwitch> nodeMap = new ConcurrentHashMap, ModelDrivenSwitch>(); - private static final LLDPSpeaker instance = new LLDPSpeaker(); - private Timer timer = new Timer(); - private static final int DELAY = 0; - private static final int PERIOD = 1000 * 5; - - private LLDPSpeaker() { - timer.schedule(new LLDPSpeakerTask(), DELAY, PERIOD); - } - - public static LLDPSpeaker getInstance() { - return instance; - } - - public void addModelDrivenSwitch(InstanceIdentifier nodeInstanceId, ModelDrivenSwitch sw) { - nodeMap.put(nodeInstanceId, sw); - } - - public void removeModelDrivenSwitch(InstanceIdentifier nodeInstanceId) { - nodeMap.remove(nodeInstanceId); - for (InstanceIdentifier nodeConnectorInstanceId : nodeConnectorMap.keySet()) { - if (nodeInstanceId.equals(nodeConnectorInstanceId.firstIdentifierOf(Node.class))) { - nodeConnectorMap.remove(nodeConnectorInstanceId); - } - } - } - - public void addNodeConnector(InstanceIdentifier nodeConnectorInstanceId, NodeConnector nodeConnector) { - InstanceIdentifier nodeInstanceId = nodeConnectorInstanceId.firstIdentifierOf(Node.class); - ModelDrivenSwitch md = nodeMap.get(nodeInstanceId); - - NodeKey nodeKey = InstanceIdentifier.keyOf(nodeInstanceId); - NodeId nodeId = nodeKey.getId(); - NodeConnectorId nodeConnectorId = nodeConnector.getId(); - FlowCapableNodeConnector flowConnector = nodeConnector.getAugmentation(FlowCapableNodeConnector.class); - TransmitPacketInputBuilder tpib = new TransmitPacketInputBuilder(); - tpib.setEgress(new NodeConnectorRef(nodeConnectorInstanceId)); - tpib.setNode(new NodeRef(nodeInstanceId)); - if(nodeInstanceId == null) { - LOG.warn("addNodeConnector(): nodeInstanceId should not be null nodeConnectorInstanceId {} nodeConnector {}",nodeConnectorInstanceId,nodeConnector); - } else if (nodeConnectorInstanceId == null) { - LOG.warn("addNodeConnector(): nodeConnectorInstanceId should not be null nodeConnectorInstanceId {} nodeConnector {}",nodeConnectorInstanceId,nodeConnector); - } else if (flowConnector == null) { - LOG.warn("addNodeConnector(): flowConnector should not be null nodeConnectorInstanceId {} nodeConnector {}",nodeConnectorInstanceId,nodeConnector); - } else if (md == null) { - LOG.debug("addNodeConnector(): md is null, this usually means your switch disconnected while you had unprocessed NodeConnectorUpdated messages in queue nodeConnectorInstanceId {} nodeConnector {}",nodeConnectorInstanceId,nodeConnector); - } else if(md.getSessionContext() == null) { - LOG.warn("addNodeConnector(): md.getSessionContext() should not be null nodeConnectorInstanceId {} nodeConnector {}",nodeConnectorInstanceId,nodeConnector); - } else if (md.getSessionContext().getPrimaryConductor() == null) { - LOG.warn("addNodeConnector(): md.getSessionContext().getPrimaryConductor() should not be null nodeConnectorInstanceId {} nodeConnector {}",nodeConnectorInstanceId,nodeConnector); - } else { - tpib.setPayload(lldpDataFrom(nodeInstanceId,nodeConnectorInstanceId,flowConnector.getHardwareAddress(), - md.getSessionContext().getPrimaryConductor().getVersion())); - nodeConnectorMap.put(nodeConnectorInstanceId, tpib.build()); - - md.transmitPacket(nodeConnectorMap.get(nodeConnectorInstanceId)); - } - } - - public void removeNodeConnector( - InstanceIdentifier nodeConnectorInstanceId, - NodeConnector nodeConnector) { - nodeConnectorMap.remove(nodeConnectorInstanceId); - } - - private byte[] lldpDataFrom(InstanceIdentifier nodeInstanceId, InstanceIdentifier nodeConnectorInstanceId, MacAddress src, - Short version) { - - NodeId nodeId = InstanceIdentifier.keyOf(nodeInstanceId).getId(); - NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(nodeConnectorInstanceId).getId(); - // Create LLDP TTL TLV - byte[] ttl = new byte[]{(byte) 0, (byte) 120}; - LLDPTLV ttlTlv = new LLDPTLV(); - ttlTlv.setType(LLDPTLV.TLVType.TTL.getValue()).setLength((short) ttl.length).setValue(ttl); - - // Create LLDP ChassisID TLV - BigInteger dataPathId = InventoryDataServiceUtil.dataPathIdFromNodeId(nodeId); - byte[] cidValue = LLDPTLV.createChassisIDTLVValue( - colonize(InventoryDataServiceUtil.bigIntegerToPaddedHex(dataPathId))); - LLDPTLV chassisIdTlv = new LLDPTLV(); - chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue()); - chassisIdTlv.setType(LLDPTLV.TLVType.ChassisID.getValue()).setLength((short) cidValue.length) - .setValue(cidValue); - - // Create LLDP SystemName TLV - byte[] snValue = LLDPTLV.createSystemNameTLVValue(nodeId.getValue()); - LLDPTLV systemNameTlv = new LLDPTLV(); - systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue()); - systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue()).setLength((short) snValue.length) - .setValue(snValue); - - // Create LLDP PortID TL - Long portNo = InventoryDataServiceUtil.portNumberfromNodeConnectorId(OpenflowVersion.get(version), nodeConnectorId); - - String hexString = Long.toHexString(portNo); - byte[] pidValue = LLDPTLV.createPortIDTLVValue(hexString); - LLDPTLV portIdTlv = new LLDPTLV(); - portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue()).setLength((short) pidValue.length).setValue(pidValue); - portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue()); - - // Create LLDP Custom TLV - byte[] customValue = LLDPTLV.createCustomTLVValue(nodeConnectorId.getValue()); - LLDPTLV customTlv = new LLDPTLV(); - customTlv.setType(LLDPTLV.TLVType.Custom.getValue()).setLength((short) customValue.length) - .setValue(customValue); - - // Create LLDP Custom Option list - List customList = Collections.singletonList(customTlv); - - // Create discovery pkt - LLDP discoveryPkt = new LLDP(); - discoveryPkt.setChassisId(chassisIdTlv).setPortId(portIdTlv).setTtl(ttlTlv).setSystemNameId(systemNameTlv) - .setOptionalTLVList(customList); - - // Create ethernet pkt - byte[] sourceMac = HexEncode.bytesFromHexString(src.getValue()); - Ethernet ethPkt = new Ethernet(); - ethPkt.setSourceMACAddress(sourceMac).setDestinationMACAddress(LLDP.LLDPMulticastMac) - .setEtherType(EtherTypes.LLDP.shortValue()).setPayload(discoveryPkt); - - try { - byte[] data = ethPkt.serialize(); - return data; - } catch (PacketException e) { - LOG.error("Error creating LLDP packet", e); - } - return null; - } - - private class LLDPSpeakerTask extends TimerTask { - - @Override - public void run() { - for (InstanceIdentifier nodeConnectorInstanceId : nodeConnectorMap.keySet()) { - InstanceIdentifier nodeInstanceId = nodeConnectorInstanceId.firstIdentifierOf(Node.class); - ModelDrivenSwitch md = nodeMap.get(nodeInstanceId); - md.transmitPacket(nodeConnectorMap.get(nodeConnectorInstanceId)); - } - - } - - } - - private String colonize(String orig) { - return orig.replaceAll("(?<=..)(..)", ":$1"); - } -} diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPSpeakerPopListener.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPSpeakerPopListener.java deleted file mode 100644 index f6aacc8212..0000000000 --- a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPSpeakerPopListener.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.openflowplugin.openflow.md.lldp; - -import org.opendaylight.openflowplugin.api.openflow.md.queue.PopListener; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortState; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class LLDPSpeakerPopListener implements PopListener { - - - @Override - public void onPop(T processedMessage) { - if (processedMessage instanceof NodeConnectorUpdated) { - NodeConnectorUpdated connector = (NodeConnectorUpdated) processedMessage; - FlowCapableNodeConnectorUpdated flowConnector = connector.getAugmentation(FlowCapableNodeConnectorUpdated.class); - if (flowConnector != null) { - InstanceIdentifier nodeConnectorInstanceId = (InstanceIdentifier) connector.getNodeConnectorRef().getValue(); - NodeConnectorBuilder ncb = new NodeConnectorBuilder(connector); - FlowCapableNodeConnectorBuilder fcncb = new FlowCapableNodeConnectorBuilder(flowConnector); - ncb.addAugmentation(FlowCapableNodeConnector.class, fcncb.build()); - PortState portState = flowConnector.getState(); - PortConfig portConfig = flowConnector.getConfiguration(); - if ((portState == null || !portState.isLinkDown()) && (portConfig == null || !portConfig.isPORTDOWN())) { - LLDPSpeaker.getInstance().addNodeConnector(nodeConnectorInstanceId, ncb.build()); - } else { - LLDPSpeaker.getInstance().removeNodeConnector(nodeConnectorInstanceId, ncb.build()); - } - } - } - } - -} diff --git a/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPSpeakerPopListenerTest.java b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPSpeakerPopListenerTest.java deleted file mode 100644 index dff4e01354..0000000000 --- a/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/lldp/LLDPSpeakerPopListenerTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - -package org.opendaylight.openflowplugin.openflow.md.lldp; - -import static org.mockito.Mockito.when; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.MockitoAnnotations; -import org.mockito.runners.MockitoJUnitRunner; -import org.opendaylight.openflowplugin.api.OFConstants; -import org.opendaylight.openflowplugin.api.openflow.md.ModelDrivenSwitch; -import org.opendaylight.openflowplugin.api.openflow.md.core.ConnectionConductor; -import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext; -import org.opendaylight.openflowplugin.openflow.md.util.OpenflowPortsUtil; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdatedBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.StateBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdatedBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; -import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -/** - * Created by Martin Bobak mbobak@cisco.com on 9/23/14. - */ -@RunWith(MockitoJUnitRunner.class) -public class LLDPSpeakerPopListenerTest { - - @MockitoAnnotations.Mock - private ModelDrivenSwitch modelDrivenSwitch; - @MockitoAnnotations.Mock - private SessionContext context; - @MockitoAnnotations.Mock - private ConnectionConductor connectionConductor; - - - @Before - public void setup() { - when(modelDrivenSwitch.getSessionContext()).thenReturn(context); - when(context.getPrimaryConductor()).thenReturn(connectionConductor); - when(connectionConductor.getVersion()).thenReturn(OFConstants.OFP_VERSION_1_3); - OpenflowPortsUtil.init(); - } - - @Test - /** - * Test method which verifies registration of nodeConnector in LLDPSpeaker. - */ - public void TestOnPop() { - LLDPSpeakerPopListener lldpSpeakerPopListener = new LLDPSpeakerPopListener(); - NodeConnectorUpdatedBuilder nodeConnectorUpdatedBuilder = new NodeConnectorUpdatedBuilder(); - FlowCapableNodeConnectorUpdatedBuilder flowCapableNodeConnectorUpdatedBuilder = new FlowCapableNodeConnectorUpdatedBuilder(); - - StateBuilder stateBuilder = new StateBuilder(); - stateBuilder.setBlocked(false); - stateBuilder.setLinkDown(false); - stateBuilder.setLive(true); - flowCapableNodeConnectorUpdatedBuilder.setState(stateBuilder.build()); - - flowCapableNodeConnectorUpdatedBuilder.setConfiguration(new PortConfig(true, true, true, false)); - flowCapableNodeConnectorUpdatedBuilder.setHardwareAddress(new MacAddress("00:00:00:00:00:00")); - nodeConnectorUpdatedBuilder.addAugmentation(FlowCapableNodeConnectorUpdated.class, flowCapableNodeConnectorUpdatedBuilder.build()); - NodeConnectorId nodeConnectorId = new NodeConnectorId("1"); - nodeConnectorUpdatedBuilder.setId(nodeConnectorId); - InstanceIdentifier instanceIdentifier = InstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(new NodeId("1"))).child(NodeConnector.class, new NodeConnectorKey(nodeConnectorId)); - NodeConnectorRef nodeConnectorRef = new NodeConnectorRef(instanceIdentifier); - - LLDPSpeaker.getInstance().addModelDrivenSwitch(instanceIdentifier.firstIdentifierOf(Node.class), modelDrivenSwitch); - - nodeConnectorUpdatedBuilder.setNodeConnectorRef(nodeConnectorRef); - lldpSpeakerPopListener.onPop(nodeConnectorUpdatedBuilder.build()); - - } - -} -- 2.36.6