2 * Copyright (c) 2014 Pacnet and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.openflowplugin.applications.lldpspeaker;
10 import com.google.common.collect.ImmutableSet;
11 import com.google.common.collect.Iterables;
12 import java.util.Collection;
13 import java.util.HashMap;
16 import javax.annotation.Nonnull;
17 import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
18 import org.opendaylight.mdsal.binding.api.DataBroker;
19 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
20 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
21 import org.opendaylight.mdsal.binding.api.DataTreeModification;
22 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
23 import org.opendaylight.openflowplugin.common.wait.SimpleTaskRetryLooper;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortState;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.State;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
32 import org.opendaylight.yangtools.concepts.ListenerRegistration;
33 import org.opendaylight.yangtools.yang.binding.DataObject;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
39 * NodeConnectorInventoryEventTranslator is listening for changes in inventory operational DOM tree
40 * and update LLDPSpeaker and topology.
42 public class NodeConnectorInventoryEventTranslator<T extends DataObject>
43 implements ClusteredDataTreeChangeListener<T>, AutoCloseable {
44 private static final Logger LOG = LoggerFactory.getLogger(NodeConnectorInventoryEventTranslator.class);
46 private static final InstanceIdentifier<State> II_TO_STATE = InstanceIdentifier.builder(Nodes.class)
47 .child(Node.class).child(NodeConnector.class).augmentation(FlowCapableNodeConnector.class)
48 .child(State.class).build();
50 private static final InstanceIdentifier<FlowCapableNodeConnector> II_TO_FLOW_CAPABLE_NODE_CONNECTOR
51 = InstanceIdentifier.builder(Nodes.class).child(Node.class).child(NodeConnector.class)
52 .augmentation(FlowCapableNodeConnector.class).build();
54 private static final long STARTUP_LOOP_TICK = 500L;
55 private static final int STARTUP_LOOP_MAX_RETRIES = 8;
57 private final ListenerRegistration<DataTreeChangeListener> listenerOnPortRegistration;
58 private final ListenerRegistration<DataTreeChangeListener> listenerOnPortStateRegistration;
59 private final Set<NodeConnectorEventsObserver> observers;
60 private final Map<InstanceIdentifier<?>, FlowCapableNodeConnector> iiToDownFlowCapableNodeConnectors
63 @SuppressWarnings("IllegalCatch")
64 public NodeConnectorInventoryEventTranslator(DataBroker dataBroker, NodeConnectorEventsObserver... observers) {
65 this.observers = ImmutableSet.copyOf(observers);
66 final DataTreeIdentifier dtiToNodeConnector = DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL,
67 II_TO_FLOW_CAPABLE_NODE_CONNECTOR);
68 final DataTreeIdentifier dtiToNodeConnectorState = DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL,
70 final SimpleTaskRetryLooper looper = new SimpleTaskRetryLooper(STARTUP_LOOP_TICK, STARTUP_LOOP_MAX_RETRIES);
72 listenerOnPortRegistration = looper.loopUntilNoException(() ->
73 dataBroker.registerDataTreeChangeListener(dtiToNodeConnector,
74 NodeConnectorInventoryEventTranslator.this));
75 listenerOnPortStateRegistration = looper.loopUntilNoException(() ->
76 dataBroker.registerDataTreeChangeListener(dtiToNodeConnectorState,
77 NodeConnectorInventoryEventTranslator.this));
78 } catch (Exception e) {
79 LOG.error("DataTreeChangeListeners registration failed: {}", e);
80 throw new IllegalStateException("NodeConnectorInventoryEventTranslator startup failed!", e);
82 LOG.info("NodeConnectorInventoryEventTranslator has started.");
87 if (listenerOnPortRegistration != null) {
88 listenerOnPortRegistration.close();
90 if (listenerOnPortStateRegistration != null) {
91 listenerOnPortStateRegistration.close();
96 public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<T>> modifications) {
97 for (DataTreeModification modification : modifications) {
98 LOG.trace("Node connectors in inventory changed -> {}", modification.getRootNode().getModificationType());
99 switch (modification.getRootNode().getModificationType()) {
101 processAddedConnector(modification);
103 case SUBTREE_MODIFIED:
104 processUpdatedConnector(modification);
107 processRemovedConnector(modification);
110 throw new IllegalArgumentException(
111 "Unhandled modification type: {}" + modification.getRootNode().getModificationType());
116 private void processAddedConnector(final DataTreeModification<T> modification) {
117 final InstanceIdentifier<T> identifier = modification.getRootPath().getRootIdentifier();
118 InstanceIdentifier<NodeConnector> nodeConnectorInstanceId = identifier.firstIdentifierOf(NodeConnector.class);
119 if (compareIITail(identifier, II_TO_FLOW_CAPABLE_NODE_CONNECTOR)) {
120 FlowCapableNodeConnector flowConnector = (FlowCapableNodeConnector) modification.getRootNode()
122 if (!isPortDown(flowConnector)) {
123 notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowConnector);
125 iiToDownFlowCapableNodeConnectors.put(nodeConnectorInstanceId, flowConnector);
130 private void processUpdatedConnector(final DataTreeModification<T> modification) {
131 final InstanceIdentifier<T> identifier = modification.getRootPath().getRootIdentifier();
132 InstanceIdentifier<NodeConnector> nodeConnectorInstanceId = identifier.firstIdentifierOf(NodeConnector.class);
133 if (compareIITail(identifier, II_TO_FLOW_CAPABLE_NODE_CONNECTOR)) {
134 FlowCapableNodeConnector flowConnector = (FlowCapableNodeConnector) modification.getRootNode()
136 if (isPortDown(flowConnector)) {
137 notifyNodeConnectorDisappeared(nodeConnectorInstanceId);
139 notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowConnector);
141 } else if (compareIITail(identifier, II_TO_STATE)) {
142 FlowCapableNodeConnector flowNodeConnector = iiToDownFlowCapableNodeConnectors.get(nodeConnectorInstanceId);
143 if (flowNodeConnector != null) {
144 State state = (State) modification.getRootNode().getDataAfter();
145 if (!state.isLinkDown()) {
146 FlowCapableNodeConnectorBuilder flowCapableNodeConnectorBuilder
147 = new FlowCapableNodeConnectorBuilder(flowNodeConnector);
148 flowCapableNodeConnectorBuilder.setState(state);
149 notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowCapableNodeConnectorBuilder.build());
150 iiToDownFlowCapableNodeConnectors.remove(nodeConnectorInstanceId);
156 private void processRemovedConnector(final DataTreeModification<T> modification) {
157 final InstanceIdentifier<T> identifier = modification.getRootPath().getRootIdentifier();
158 if (compareIITail(identifier, II_TO_FLOW_CAPABLE_NODE_CONNECTOR)) {
159 InstanceIdentifier<NodeConnector> nodeConnectorInstanceId = identifier
160 .firstIdentifierOf(NodeConnector.class);
161 notifyNodeConnectorDisappeared(nodeConnectorInstanceId);
165 private boolean compareIITail(final InstanceIdentifier<?> ii1, final InstanceIdentifier<?> ii2) {
166 return Iterables.getLast(ii1.getPathArguments()).equals(Iterables.getLast(ii2.getPathArguments()));
169 private static boolean isPortDown(final FlowCapableNodeConnector flowCapableNodeConnector) {
170 PortState portState = flowCapableNodeConnector.getState();
171 PortConfig portConfig = flowCapableNodeConnector.getConfiguration();
172 return portState != null && portState.isLinkDown() || portConfig != null && portConfig.isPORTDOWN();
175 private void notifyNodeConnectorAppeared(final InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,
176 final FlowCapableNodeConnector flowConnector) {
177 for (NodeConnectorEventsObserver observer : observers) {
178 observer.nodeConnectorAdded(nodeConnectorInstanceId, flowConnector);
182 private void notifyNodeConnectorDisappeared(final InstanceIdentifier<NodeConnector> nodeConnectorInstanceId) {
183 for (NodeConnectorEventsObserver observer : observers) {
184 observer.nodeConnectorRemoved(nodeConnectorInstanceId);