<groupId>org.opendaylight.openflowplugin.model</groupId>
<artifactId>model-flow-service</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.openflowplugin</groupId>
+ <artifactId>openflowplugin-common</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
* 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);
+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<InstanceIdentifier<NodeConnector>, TransmitPacketInput> nodeConnectorMap = new ConcurrentHashMap<>();
+ private final Map<InstanceIdentifier<NodeConnector>, TransmitPacketInput> nodeConnectorMap =
+ new ConcurrentHashMap<>();
private final ScheduledFuture<?> scheduledSpeakerTask;
private final MacAddress addressDestionation;
private volatile OperStatus operationalStatus = OperStatus.RUN;
- public LLDPSpeaker(final PacketProcessingService packetProcessingService,
- final MacAddress addressDestionation) {
- this(packetProcessingService, Executors
- .newSingleThreadScheduledExecutor(), addressDestionation);
+ public LLDPSpeaker(final PacketProcessingService packetProcessingService, final MacAddress addressDestionation) {
+ this(packetProcessingService, Executors.newSingleThreadScheduledExecutor(), addressDestionation);
}
public void setOperationalStatus(final OperStatus operationalStatus) {
}
public LLDPSpeaker(final PacketProcessingService packetProcessingService,
- final ScheduledExecutorService scheduledExecutorService,
- final MacAddress addressDestionation) {
+ final ScheduledExecutorService scheduledExecutorService,
+ final MacAddress addressDestionation) {
this.addressDestionation = addressDestionation;
this.scheduledExecutorService = scheduledExecutorService;
scheduledSpeakerTask = this.scheduledExecutorService
- .scheduleAtFixedRate(this, LLDP_FLOOD_PERIOD,
- LLDP_FLOOD_PERIOD, TimeUnit.SECONDS);
+ .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);
+ LOG.info("LLDPSpeaker started, it will send LLDP frames each {} seconds", LLDP_FLOOD_PERIOD);
}
/**
@Override
public void run() {
if (OperStatus.RUN.equals(operationalStatus)) {
- LOG.debug("Sending LLDP frames to {} ports...", nodeConnectorMap
- .keySet().size());
-
- for (InstanceIdentifier<NodeConnector> nodeConnectorInstanceId : nodeConnectorMap
- .keySet()) {
- NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(
- nodeConnectorInstanceId).getId();
- LOG.trace("Sending LLDP through port {}",
- nodeConnectorId.getValue());
- packetProcessingService.transmitPacket(nodeConnectorMap
- .get(nodeConnectorInstanceId));
+ LOG.debug("Sending LLDP frames to {} ports...", nodeConnectorMap.keySet().size());
+ for (InstanceIdentifier<NodeConnector> 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(
- final InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,
- final FlowCapableNodeConnector flowConnector) {
- NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(
- nodeConnectorInstanceId).getId();
+ public void nodeConnectorAdded(final InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,
+ final FlowCapableNodeConnector flowConnector) {
+ NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(nodeConnectorInstanceId).getId();
// nodeConnectorAdded can be called even if we already sending LLDP
// frames to
}
// Prepare to build LLDP payload
- InstanceIdentifier<Node> nodeInstanceId = nodeConnectorInstanceId
- .firstIdentifierOf(Node.class);
+ InstanceIdentifier<Node> 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());
+ LOG.trace("Port {} is local, not sending LLDP frames through it", nodeConnectorId.getValue());
return;
}
TransmitPacketInput packet = new TransmitPacketInputBuilder()
.setEgress(new NodeConnectorRef(nodeConnectorInstanceId))
.setNode(new NodeRef(nodeInstanceId))
- .setPayload(
- LLDPUtil.buildLldpFrame(nodeId, nodeConnectorId,
- srcMacAddress, outputPortNo,
- addressDestionation)).build();
+ .setPayload(LLDPUtil
+ .buildLldpFrame(nodeId, nodeConnectorId, srcMacAddress, outputPortNo, addressDestionation))
+ .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());
+ LOG.trace("Port {} added to LLDPSpeaker.nodeConnectorMap", nodeConnectorId.getValue());
// Transmit packet for first time immediately
packetProcessingService.transmitPacket(packet);
* {@inheritDoc}
*/
@Override
- public void nodeConnectorRemoved(
- final InstanceIdentifier<NodeConnector> nodeConnectorInstanceId) {
+ public void nodeConnectorRemoved(final InstanceIdentifier<NodeConnector> nodeConnectorInstanceId) {
nodeConnectorMap.remove(nodeConnectorInstanceId);
- NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(
- nodeConnectorInstanceId).getId();
- LOG.trace("Port {} removed from LLDPSpeaker.nodeConnectorMap",
- nodeConnectorId.getValue());
+ NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(nodeConnectorInstanceId).getId();
+ LOG.trace("Port {} removed from LLDPSpeaker.nodeConnectorMap", nodeConnectorId.getValue());
}
+
}
import static org.opendaylight.controller.liblldp.LLDPTLV.CUSTOM_TLV_SUB_TYPE_CUSTOM_SEC;
import static org.opendaylight.openflowplugin.applications.topology.lldp.utils.LLDPDiscoveryUtils.getValueForLLDPPacketIntegrityEnsuring;
+
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.lang3.StringUtils;
private static final String OF_URI_PREFIX = "openflow:";
static byte[] buildLldpFrame(final NodeId nodeId,
- final NodeConnectorId nodeConnectorId, final MacAddress src, final Long outPortNo,
- final MacAddress destinationAddress) {
+ final NodeConnectorId nodeConnectorId,
+ final MacAddress src,
+ final Long outPortNo,
+ final MacAddress destinationAddress) {
// Create discovery pkt
LLDP discoveryPkt = new LLDP();
// Create LLDP ChassisID TLV
BigInteger dataPathId = dataPathIdFromNodeId(nodeId);
- byte[] cidValue = LLDPTLV
- .createChassisIDTLVValue(colonize(bigIntegerToPaddedHex(dataPathId)));
+ 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);
+ .setLength((short) cidValue.length)
+ .setValue(cidValue);
discoveryPkt.setChassisId(chassisIdTlv);
// Create LLDP PortID TL
byte[] pidValue = LLDPTLV.createPortIDTLVValue(hexString);
LLDPTLV portIdTlv = new LLDPTLV();
portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue())
- .setLength((short) pidValue.length).setValue(pidValue);
+ .setLength((short) pidValue.length)
+ .setValue(pidValue);
portIdTlv.setType(LLDPTLV.TLVType.PortID.getValue());
discoveryPkt.setPortId(portIdTlv);
// 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);
+ ttlTlv.setType(LLDPTLV.TLVType.TTL.getValue()).setLength((short) ttl.length).setValue(ttl);
discoveryPkt.setTtl(ttlTlv);
// Create LLDP SystemName TLV
LLDPTLV systemNameTlv = new LLDPTLV();
systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue());
systemNameTlv.setType(LLDPTLV.TLVType.SystemName.getValue())
- .setLength((short) snValue.length).setValue(snValue);
+ .setLength((short) snValue.length)
+ .setValue(snValue);
discoveryPkt.setSystemNameId(systemNameTlv);
// Create LLDP Custom TLV
- byte[] customValue = LLDPTLV.createCustomTLVValue(nodeConnectorId
- .getValue());
+ byte[] customValue = LLDPTLV.createCustomTLVValue(nodeConnectorId.getValue());
LLDPTLV customTlv = new LLDPTLV();
customTlv.setType(LLDPTLV.TLVType.Custom.getValue())
- .setLength((short) customValue.length).setValue(customValue);
+ .setLength((short) customValue.length)
+ .setValue(customValue);
discoveryPkt.addCustomTLV(customTlv);
//Create LLDP CustomSec TLV
byte[] customSecValue = LLDPTLV.createCustomTLVValue(CUSTOM_TLV_SUB_TYPE_CUSTOM_SEC, pureValue);
LLDPTLV customSecTlv = new LLDPTLV();
customSecTlv.setType(LLDPTLV.TLVType.Custom.getValue())
- .setLength((short)customSecValue.length)
- .setValue(customSecValue);
+ .setLength((short)customSecValue.length)
+ .setValue(customSecValue);
discoveryPkt.addCustomTLV(customSecTlv);
} catch (NoSuchAlgorithmException e1) {
LOG.info("LLDP extra authenticator creation failed: {}", e1.getMessage());
byte[] sourceMac = HexEncode.bytesFromHexString(src.getValue());
Ethernet ethPkt = new Ethernet();
ethPkt.setSourceMACAddress(sourceMac)
- .setEtherType(EtherTypes.LLDP.shortValue())
- .setPayload(discoveryPkt);
+ .setEtherType(EtherTypes.LLDP.shortValue())
+ .setPayload(discoveryPkt);
if (destinationAddress == null) {
ethPkt.setDestinationMACAddress(LLDP.LLDPMulticastMac);
} else {
- ethPkt.setDestinationMACAddress(HexEncode
- .bytesFromHexString(destinationAddress.getValue()));
+ ethPkt.setDestinationMACAddress(HexEncode.bytesFromHexString(destinationAddress.getValue()));
}
try {
}
static byte[] buildLldpFrame(final NodeId nodeId,
- final NodeConnectorId nodeConnectorId, final MacAddress srcMacAddress,
- final Long outputPortNo) {
- return buildLldpFrame(nodeId, nodeConnectorId, srcMacAddress,
- outputPortNo, null);
+ final NodeConnectorId nodeConnectorId,
+ final MacAddress srcMacAddress,
+ final Long outputPortNo) {
+ return buildLldpFrame(nodeId, nodeConnectorId, srcMacAddress, outputPortNo, null);
}
}
* @param nodeConnectorInstanceId Object that uniquely identify added node connector
* @param flowConnector object containing almost all of details about node connector
*/
- public void nodeConnectorAdded(InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,
+ void nodeConnectorAdded(InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,
FlowCapableNodeConnector flowConnector);
/**
* the same removal event.
* @param nodeConnectorInstanceId Object that uniquely identify added node connector
*/
- public void nodeConnectorRemoved(InstanceIdentifier<NodeConnector> nodeConnectorInstanceId);
+ void nodeConnectorRemoved(InstanceIdentifier<NodeConnector> nodeConnectorInstanceId);
}
package org.opendaylight.openflowplugin.applications.lldpspeaker;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.State;
+import java.util.Collection;
import java.util.HashMap;
-import com.google.common.collect.ImmutableSet;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.Callable;
+import javax.annotation.Nonnull;
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.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.openflowplugin.common.wait.SimpleTaskRetryLooper;
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.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.flow.types.port.rev130925.flow.capable.port.State;
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.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 InstanceIdentifier<State> II_TO_STATE
+public class NodeConnectorInventoryEventTranslator<T extends DataObject>
+ implements DataTreeChangeListener<T>, AutoCloseable {
+
+ private static final InstanceIdentifier<State> II_TO_STATE
= InstanceIdentifier.builder(Nodes.class)
.child(Node.class)
.child(NodeConnector.class)
.augmentation(FlowCapableNodeConnector.class)
.build();
+ private static final long STARTUP_LOOP_TICK = 500L;
+ private static final int STARTUP_LOOP_MAX_RETRIES = 8;
private static final Logger LOG = LoggerFactory.getLogger(NodeConnectorInventoryEventTranslator.class);
- private final ListenerRegistration<DataChangeListener> dataChangeListenerRegistration;
- private final ListenerRegistration<DataChangeListener> listenerOnPortStateRegistration;
+ private final ListenerRegistration<DataTreeChangeListener> dataChangeListenerRegistration;
+ private final ListenerRegistration<DataTreeChangeListener> listenerOnPortStateRegistration;
private final Set<NodeConnectorEventsObserver> observers;
private final Map<InstanceIdentifier<?>,FlowCapableNodeConnector> iiToDownFlowCapableNodeConnectors = new HashMap<>();
public NodeConnectorInventoryEventTranslator(DataBroker dataBroker, NodeConnectorEventsObserver... observers) {
this.observers = ImmutableSet.copyOf(observers);
- dataChangeListenerRegistration = dataBroker.registerDataChangeListener(
- LogicalDatastoreType.OPERATIONAL,
- II_TO_FLOW_CAPABLE_NODE_CONNECTOR,
- this, AsyncDataBroker.DataChangeScope.BASE);
- listenerOnPortStateRegistration = dataBroker.registerDataChangeListener(
- LogicalDatastoreType.OPERATIONAL,
- II_TO_STATE,
- this, AsyncDataBroker.DataChangeScope.SUBTREE);
+ final DataTreeIdentifier<T> dtiToNodeConnector =
+ new DataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, II_TO_FLOW_CAPABLE_NODE_CONNECTOR);
+ final DataTreeIdentifier<T> dtiToNodeConnectorState =
+ new DataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, II_TO_STATE);
+ final SimpleTaskRetryLooper looper = new SimpleTaskRetryLooper(STARTUP_LOOP_TICK, STARTUP_LOOP_MAX_RETRIES);
+ try {
+ dataChangeListenerRegistration = looper.loopUntilNoException(new Callable<ListenerRegistration<DataTreeChangeListener>>() {
+ @Override
+ public ListenerRegistration<DataTreeChangeListener> call() throws Exception {
+ return dataBroker.registerDataTreeChangeListener(dtiToNodeConnector, NodeConnectorInventoryEventTranslator.this);
+ }
+ });
+ listenerOnPortStateRegistration = looper.loopUntilNoException(new Callable<ListenerRegistration<DataTreeChangeListener>>() {
+ @Override
+ public ListenerRegistration<DataTreeChangeListener> call() throws Exception {
+ return dataBroker.registerDataTreeChangeListener(dtiToNodeConnectorState, NodeConnectorInventoryEventTranslator.this);
+ }
+ });
+ } catch (Exception e) {
+ LOG.error("DataTreeChangeListeners registration failed: {}", e);
+ throw new IllegalStateException("NodeConnectorInventoryEventTranslator startup failed!", e);
+ }
+ LOG.info("NodeConnectorInventoryEventTranslator has started.");
}
@Override
public void close() {
- dataChangeListenerRegistration.close();
- listenerOnPortStateRegistration.close();
+ if (dataChangeListenerRegistration != null) {
+ dataChangeListenerRegistration.close();
+ }
+ if (listenerOnPortStateRegistration != null) {
+ listenerOnPortStateRegistration.close();
+ }
}
@Override
- public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, 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<InstanceIdentifier<?>, DataObject> entry : change.getCreatedData().entrySet()) {
- InstanceIdentifier<NodeConnector> nodeConnectorInstanceId =
- entry.getKey().firstIdentifierOf(NodeConnector.class);
- if (compareIITail(entry.getKey(),II_TO_FLOW_CAPABLE_NODE_CONNECTOR)) {
- FlowCapableNodeConnector flowConnector = (FlowCapableNodeConnector) entry.getValue();
- if (!isPortDown(flowConnector)) {
- notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowConnector);
- } else {
- iiToDownFlowCapableNodeConnectors.put(nodeConnectorInstanceId, flowConnector);
- }
+ public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<T>> modifications) {
+ for(DataTreeModification modification : modifications) {
+ LOG.trace("Node connectors in inventory changed -> {}", modification.getRootNode().getModificationType());
+ switch (modification.getRootNode().getModificationType()) {
+ case WRITE:
+ processAddedConnector(modification);
+ break;
+ case SUBTREE_MODIFIED:
+ processUpdatedConnector(modification);
+ break;
+ case DELETE:
+ processRemovedConnector(modification);
+ break;
+ default:
+ throw new IllegalArgumentException("Unhandled modification type: {}" +
+ modification.getRootNode().getModificationType());
}
}
+ }
- // Iterate over updated node connectors (port down state may change)
- for (Map.Entry<InstanceIdentifier<?>, DataObject> entry : change.getUpdatedData().entrySet()) {
- InstanceIdentifier<NodeConnector> nodeConnectorInstanceId =
- entry.getKey().firstIdentifierOf(NodeConnector.class);
- if (compareIITail(entry.getKey(),II_TO_FLOW_CAPABLE_NODE_CONNECTOR)) {
- FlowCapableNodeConnector flowConnector = (FlowCapableNodeConnector) entry.getValue();
- if (isPortDown(flowConnector)) {
- notifyNodeConnectorDisappeared(nodeConnectorInstanceId);
- } else {
- notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowConnector);
- }
- } else if (compareIITail(entry.getKey(),II_TO_STATE)) {
- FlowCapableNodeConnector flowNodeConnector = iiToDownFlowCapableNodeConnectors.get(nodeConnectorInstanceId);
- if (flowNodeConnector != null) {
- State state = (State)entry.getValue();
- if (!state.isLinkDown()) {
- FlowCapableNodeConnectorBuilder flowCapableNodeConnectorBuilder = new FlowCapableNodeConnectorBuilder(flowNodeConnector);
- flowCapableNodeConnectorBuilder.setState(state);
- notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowCapableNodeConnectorBuilder.build());
- iiToDownFlowCapableNodeConnectors.remove(nodeConnectorInstanceId);
- }
- }
+ private void processAddedConnector(final DataTreeModification<T> modification) {
+ final InstanceIdentifier<T> identifier = modification.getRootPath().getRootIdentifier();
+ InstanceIdentifier<NodeConnector> nodeConnectorInstanceId =identifier.firstIdentifierOf(NodeConnector.class);
+ if (compareIITail(identifier, II_TO_FLOW_CAPABLE_NODE_CONNECTOR)) {
+ FlowCapableNodeConnector flowConnector = (FlowCapableNodeConnector) modification.getRootNode().getDataAfter();
+ if (!isPortDown(flowConnector)) {
+ notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowConnector);
+ } else {
+ iiToDownFlowCapableNodeConnectors.put(nodeConnectorInstanceId, flowConnector);
}
}
+ }
- // Iterate over removed node connectors
- for (InstanceIdentifier<?> removed : change.getRemovedPaths()) {
- if (compareIITail(removed,II_TO_FLOW_CAPABLE_NODE_CONNECTOR)) {
- InstanceIdentifier<NodeConnector> nodeConnectorInstanceId = removed.firstIdentifierOf(NodeConnector.class);
+ private void processUpdatedConnector(final DataTreeModification<T> modification) {
+ final InstanceIdentifier<T> identifier = modification.getRootPath().getRootIdentifier();
+ InstanceIdentifier<NodeConnector> nodeConnectorInstanceId = identifier.firstIdentifierOf(NodeConnector.class);
+ if (compareIITail(identifier, II_TO_FLOW_CAPABLE_NODE_CONNECTOR)) {
+ FlowCapableNodeConnector flowConnector = (FlowCapableNodeConnector) modification.getRootNode().getDataAfter();
+ if (isPortDown(flowConnector)) {
notifyNodeConnectorDisappeared(nodeConnectorInstanceId);
+ } else {
+ notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowConnector);
}
+ } else if (compareIITail(identifier, II_TO_STATE)) {
+ FlowCapableNodeConnector flowNodeConnector = iiToDownFlowCapableNodeConnectors.get(nodeConnectorInstanceId);
+ if (flowNodeConnector != null) {
+ State state = (State) modification.getRootNode().getDataAfter();
+ if (!state.isLinkDown()) {
+ FlowCapableNodeConnectorBuilder flowCapableNodeConnectorBuilder =
+ new FlowCapableNodeConnectorBuilder(flowNodeConnector);
+ flowCapableNodeConnectorBuilder.setState(state);
+ notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowCapableNodeConnectorBuilder.build());
+ iiToDownFlowCapableNodeConnectors.remove(nodeConnectorInstanceId);
+ }
+ }
+ }
+ }
+
+ private void processRemovedConnector(final DataTreeModification<T> modification) {
+ final InstanceIdentifier<T> identifier = modification.getRootPath().getRootIdentifier();
+ if (compareIITail(identifier, II_TO_FLOW_CAPABLE_NODE_CONNECTOR)) {
+ InstanceIdentifier<NodeConnector> nodeConnectorInstanceId = identifier.firstIdentifierOf(NodeConnector.class);
+ notifyNodeConnectorDisappeared(nodeConnectorInstanceId);
}
}
- /**
- * @param key
- * @param iiToFlowCapableNodeConnector
- * @return
- */
- private boolean compareIITail(InstanceIdentifier<?> ii1,
- InstanceIdentifier<?> ii2) {
+ private boolean compareIITail(final InstanceIdentifier<?> ii1, final InstanceIdentifier<?> ii2) {
return Iterables.getLast(ii1.getPathArguments()).equals(Iterables.getLast(ii2.getPathArguments()));
}
- private static boolean isPortDown(FlowCapableNodeConnector flowCapableNodeConnector) {
+ private static boolean isPortDown(final FlowCapableNodeConnector flowCapableNodeConnector) {
PortState portState = flowCapableNodeConnector.getState();
PortConfig portConfig = flowCapableNodeConnector.getConfiguration();
- return portState != null && portState.isLinkDown() ||
- portConfig != null && portConfig.isPORTDOWN();
+ return portState != null && portState.isLinkDown()
+ || portConfig != null && portConfig.isPORTDOWN();
}
- private void notifyNodeConnectorAppeared(InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,
- FlowCapableNodeConnector flowConnector) {
+ private void notifyNodeConnectorAppeared(final InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,
+ final FlowCapableNodeConnector flowConnector) {
for (NodeConnectorEventsObserver observer : observers) {
observer.nodeConnectorAdded(nodeConnectorInstanceId, flowConnector);
}
}
- private void notifyNodeConnectorDisappeared(InstanceIdentifier<NodeConnector> nodeConnectorInstanceId) {
+ private void notifyNodeConnectorDisappeared(final InstanceIdentifier<NodeConnector> nodeConnectorInstanceId) {
for (NodeConnectorEventsObserver observer : observers) {
observer.nodeConnectorRemoved(nodeConnectorInstanceId);
}
}
+
}
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
-/**
- * Created by Martin Bobak mbobak@cisco.com on 11/20/14.
- */
public class OperationalStatusChangeService implements LldpSpeakerService {
private final LLDPSpeaker speakerInstance;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
*/
@RunWith(MockitoJUnitRunner.class)
public class LLDPSpeakerTest {
- static InstanceIdentifier<NodeConnector> id;
- static FlowCapableNodeConnector fcnc;
- static TransmitPacketInput packet;
+ private static final InstanceIdentifier<NodeConnector> id;
+ private static final FlowCapableNodeConnector fcnc;
+ private static final TransmitPacketInput packet;
static {
MacAddress mac = new MacAddress("01:23:45:67:89:AB");
}
@Mock
- PacketProcessingService packetProcessingService;
+ private PacketProcessingService packetProcessingService;
@Mock
- ScheduledExecutorService scheduledExecutorService;
+ private ScheduledExecutorService scheduledExecutorService;
@Mock
- ScheduledFuture scheduledSpeakerTask;
+ private ScheduledFuture scheduledSpeakerTask;
- MacAddress destinationMACAddress = null;
- LLDPSpeaker lldpSpeaker;
+ private final MacAddress destinationMACAddress = null;
+ private LLDPSpeaker lldpSpeaker;
@Before
@SuppressWarnings("unchecked")
/**
* Test that lldpSpeaker cancels periodic LLDP flood task and stops
- *
- * @{ScheduledExecutorService .
- * @throws Exception
*/
@Test
- public void testCleanup() throws Exception {
+ public void testCleanup() {
lldpSpeaker.close();
verify(scheduledSpeakerTask, times(1)).cancel(true);
verify(scheduledExecutorService, times(1)).shutdown();
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 static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+import static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType.DELETE;
+import static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType.SUBTREE_MODIFIED;
+import static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType.WRITE;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
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.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
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;
*/
@RunWith(MockitoJUnitRunner.class)
public class NodeConnectorInventoryEventTranslatorTest {
- static InstanceIdentifier<NodeConnector> id = TestUtils.createNodeConnectorId("openflow:1", "openflow:1:1");
- static InstanceIdentifier<FlowCapableNodeConnector> iiToConnector = id.augmentation(FlowCapableNodeConnector.class);
- static FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector().build();
+ private static final InstanceIdentifier<NodeConnector> id = TestUtils.createNodeConnectorId("openflow:1", "openflow:1:1");
+ private static final InstanceIdentifier<FlowCapableNodeConnector> iiToConnector = id.augmentation(FlowCapableNodeConnector.class);
+ private static final FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector().build();
- @Mock DataBroker dataBroker;
- @Mock ListenerRegistration<DataChangeListener> dataChangeListenerRegistration;
- @Mock NodeConnectorEventsObserver eventsObserver;
- @Mock NodeConnectorEventsObserver eventsObserver2;
+ @Mock
+ private NodeConnectorEventsObserver eventsObserver;
+ @Mock
+ private NodeConnectorEventsObserver eventsObserver2;
- MockDataChangedEvent dataChangedEvent = new MockDataChangedEvent();
- NodeConnectorInventoryEventTranslator translator;
+ private 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);
+ translator = new NodeConnectorInventoryEventTranslator(mock(DataBroker.class), eventsObserver, eventsObserver2);
}
/**
*/
@Test
public void testNodeConnectorCreation() {
- // Setup dataChangedEvent to mock new port creation in inventory
- dataChangedEvent.created.put(iiToConnector, fcnc);
-
- // Invoke NodeConnectorInventoryEventTranslator and check result
- translator.onDataChanged(dataChangedEvent);
+ DataTreeModification dataTreeModification = setupDataTreeChange(WRITE, iiToConnector, fcnc);
+ translator.onDataTreeChanged(Collections.singleton(dataTreeModification));
verify(eventsObserver).nodeConnectorAdded(id, fcnc);
}
@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);
+ DataTreeModification dataTreeModification = setupDataTreeChange(WRITE, id, fcnc);
+ translator.onDataTreeChanged(Collections.singleton(dataTreeModification));
verifyZeroInteractions(eventsObserver);
}
@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);
+ DataTreeModification dataTreeModification = setupDataTreeChange(WRITE, id, fcnc);
+ translator.onDataTreeChanged(Collections.singleton(dataTreeModification));
verifyZeroInteractions(eventsObserver);
}
@Test
public void testNodeConnectorUpdateToLinkDown() {
FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector(true, false).build();
-
- // Setup dataChangedEvent to mock link down
- dataChangedEvent.updated.put(iiToConnector, fcnc);
-
- // Invoke NodeConnectorInventoryEventTranslator and check result
- translator.onDataChanged(dataChangedEvent);
+ DataTreeModification dataTreeModification = setupDataTreeChange(SUBTREE_MODIFIED, iiToConnector, fcnc);
+ translator.onDataTreeChanged(Collections.singleton(dataTreeModification));
verify(eventsObserver).nodeConnectorRemoved(id);
}
@Test
public void testNodeConnectorUpdateToAdminDown() {
FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector(false, true).build();
-
- // Setup dataChangedEvent to mock link down and administrative port down
- dataChangedEvent.updated.put(iiToConnector, fcnc);
-
- // Invoke NodeConnectorInventoryEventTranslator and check result
- translator.onDataChanged(dataChangedEvent);
+ DataTreeModification dataTreeModification = setupDataTreeChange(SUBTREE_MODIFIED, iiToConnector, fcnc);
+ translator.onDataTreeChanged(Collections.singleton(dataTreeModification));
verify(eventsObserver).nodeConnectorRemoved(id);
}
*/
@Test
public void testNodeConnectorUpdateToUp() {
- // Setup dataChangedEvent to mock link up and administrative port up
- dataChangedEvent.updated.put(iiToConnector, fcnc);
-
- // Invoke NodeConnectorInventoryEventTranslator and check result
- translator.onDataChanged(dataChangedEvent);
+ DataTreeModification dataTreeModification = setupDataTreeChange(SUBTREE_MODIFIED, iiToConnector, fcnc);
+ translator.onDataTreeChanged(Collections.singleton(dataTreeModification));
verify(eventsObserver).nodeConnectorAdded(id, fcnc);
}
*/
@Test
public void testNodeConnectorRemoval() {
- // Setup dataChangedEvent to mock node connector removal
- dataChangedEvent.removed.add(iiToConnector);
-
+ DataTreeModification dataTreeModification = setupDataTreeChange(DELETE, iiToConnector, null);
// Invoke NodeConnectorInventoryEventTranslator and check result
- translator.onDataChanged(dataChangedEvent);
+ translator.onDataTreeChanged(Collections.singleton(dataTreeModification));
verify(eventsObserver).nodeConnectorRemoved(id);
}
// Create prerequisites
InstanceIdentifier<NodeConnector> id2 = TestUtils.createNodeConnectorId("openflow:1", "openflow:1:2");
InstanceIdentifier<FlowCapableNodeConnector> iiToConnector2 = id2.augmentation(FlowCapableNodeConnector.class);
-
- // Setup dataChangedEvent to mock port creation and removal
- dataChangedEvent.created.put(iiToConnector, fcnc);
- dataChangedEvent.removed.add(iiToConnector2);
-
+ List<DataTreeModification> modifications = new ArrayList();
+ modifications.add(setupDataTreeChange(WRITE, iiToConnector, fcnc));
+ modifications.add(setupDataTreeChange(DELETE, iiToConnector2, null));
// Invoke onDataChanged and check that both observers notified
- translator.onDataChanged(dataChangedEvent);
+ translator.onDataTreeChanged(modifications);
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
+ public void tearDown() throws Exception {
translator.close();
-
- // Verify that ListenerRegistration to DOM events
- verify(dataChangeListenerRegistration, times(2)).close();
}
- static class MockDataChangedEvent implements AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> {
- Map<InstanceIdentifier<?>,DataObject> created = new HashMap<>();
- Map<InstanceIdentifier<?>,DataObject> updated = new HashMap<>();
- Set<InstanceIdentifier<?>> removed = new HashSet<>();
-
- @Override
- public Map<InstanceIdentifier<?>, DataObject> getCreatedData() {
- return created;
- }
-
- @Override
- public Map<InstanceIdentifier<?>, DataObject> getUpdatedData() {
- return updated;
- }
-
- @Override
- public Set<InstanceIdentifier<?>> getRemovedPaths() {
- return removed;
- }
-
- @Override
- public Map<InstanceIdentifier<?>, 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");
- }
+ private <T extends DataObject> DataTreeModification setupDataTreeChange(final ModificationType type,
+ final InstanceIdentifier<T> ii,
+ final FlowCapableNodeConnector connector) {
+ final DataTreeModification dataTreeModification = mock(DataTreeModification.class);
+ when(dataTreeModification.getRootNode()).thenReturn(mock(DataObjectModification.class));
+ DataTreeIdentifier<T> identifier = new DataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, ii);
+ when(dataTreeModification.getRootNode().getModificationType()).thenReturn(type);
+ when(dataTreeModification.getRootPath()).thenReturn(identifier);
+ when(dataTreeModification.getRootNode().getDataAfter()).thenReturn(connector);
+ return dataTreeModification;
+
}
}
return createFlowCapableNodeConnector(false, false, mac, port);
}
- static FlowCapableNodeConnectorBuilder createFlowCapableNodeConnector(boolean linkDown, boolean adminDown,
+ private static FlowCapableNodeConnectorBuilder createFlowCapableNodeConnector(boolean linkDown, boolean adminDown,
MacAddress mac, long port) {
return new FlowCapableNodeConnectorBuilder()
.setHardwareAddress(mac)