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
9 package org.opendaylight.openflowplugin.applications.lldpspeaker;
11 import com.google.common.collect.ImmutableSet;
12 import com.google.common.collect.Iterables;
13 import java.util.Collection;
14 import java.util.HashMap;
17 import java.util.concurrent.Callable;
18 import javax.annotation.Nonnull;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
21 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
22 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.openflowplugin.common.wait.SimpleTaskRetryLooper;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortConfig;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortState;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.flow.capable.port.State;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
33 import org.opendaylight.yangtools.concepts.ListenerRegistration;
34 import org.opendaylight.yangtools.yang.binding.DataObject;
35 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
40 * NodeConnectorInventoryEventTranslator is listening for changes in inventory operational DOM tree
41 * and update LLDPSpeaker and topology.
43 public class NodeConnectorInventoryEventTranslator<T extends DataObject>
44 implements DataTreeChangeListener<T>, AutoCloseable {
46 private static final InstanceIdentifier<State> II_TO_STATE
47 = InstanceIdentifier.builder(Nodes.class)
49 .child(NodeConnector.class)
50 .augmentation(FlowCapableNodeConnector.class)
54 private static final InstanceIdentifier<FlowCapableNodeConnector> II_TO_FLOW_CAPABLE_NODE_CONNECTOR
55 = InstanceIdentifier.builder(Nodes.class)
57 .child(NodeConnector.class)
58 .augmentation(FlowCapableNodeConnector.class)
61 private static final long STARTUP_LOOP_TICK = 500L;
62 private static final int STARTUP_LOOP_MAX_RETRIES = 8;
63 private static final Logger LOG = LoggerFactory.getLogger(NodeConnectorInventoryEventTranslator.class);
65 private final ListenerRegistration<DataTreeChangeListener> dataChangeListenerRegistration;
66 private final ListenerRegistration<DataTreeChangeListener> listenerOnPortStateRegistration;
67 private final Set<NodeConnectorEventsObserver> observers;
68 private final Map<InstanceIdentifier<?>,FlowCapableNodeConnector> iiToDownFlowCapableNodeConnectors = new HashMap<>();
70 public NodeConnectorInventoryEventTranslator(DataBroker dataBroker, NodeConnectorEventsObserver... observers) {
71 this.observers = ImmutableSet.copyOf(observers);
72 final DataTreeIdentifier<T> dtiToNodeConnector =
73 new DataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, II_TO_FLOW_CAPABLE_NODE_CONNECTOR);
74 final DataTreeIdentifier<T> dtiToNodeConnectorState =
75 new DataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, II_TO_STATE);
76 final SimpleTaskRetryLooper looper = new SimpleTaskRetryLooper(STARTUP_LOOP_TICK, STARTUP_LOOP_MAX_RETRIES);
78 dataChangeListenerRegistration = looper.loopUntilNoException(new Callable<ListenerRegistration<DataTreeChangeListener>>() {
80 public ListenerRegistration<DataTreeChangeListener> call() throws Exception {
81 return dataBroker.registerDataTreeChangeListener(dtiToNodeConnector, NodeConnectorInventoryEventTranslator.this);
84 listenerOnPortStateRegistration = looper.loopUntilNoException(new Callable<ListenerRegistration<DataTreeChangeListener>>() {
86 public ListenerRegistration<DataTreeChangeListener> call() throws Exception {
87 return dataBroker.registerDataTreeChangeListener(dtiToNodeConnectorState, NodeConnectorInventoryEventTranslator.this);
90 } catch (Exception e) {
91 LOG.error("DataTreeChangeListeners registration failed: {}", e);
92 throw new IllegalStateException("NodeConnectorInventoryEventTranslator startup failed!", e);
94 LOG.info("NodeConnectorInventoryEventTranslator has started.");
99 if (dataChangeListenerRegistration != null) {
100 dataChangeListenerRegistration.close();
102 if (listenerOnPortStateRegistration != null) {
103 listenerOnPortStateRegistration.close();
108 public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<T>> modifications) {
109 for(DataTreeModification modification : modifications) {
110 LOG.trace("Node connectors in inventory changed -> {}", modification.getRootNode().getModificationType());
111 switch (modification.getRootNode().getModificationType()) {
113 processAddedConnector(modification);
115 case SUBTREE_MODIFIED:
116 processUpdatedConnector(modification);
119 processRemovedConnector(modification);
122 throw new IllegalArgumentException("Unhandled modification type: {}" +
123 modification.getRootNode().getModificationType());
128 private void processAddedConnector(final DataTreeModification<T> modification) {
129 final InstanceIdentifier<T> identifier = modification.getRootPath().getRootIdentifier();
130 InstanceIdentifier<NodeConnector> nodeConnectorInstanceId =identifier.firstIdentifierOf(NodeConnector.class);
131 if (compareIITail(identifier, II_TO_FLOW_CAPABLE_NODE_CONNECTOR)) {
132 FlowCapableNodeConnector flowConnector = (FlowCapableNodeConnector) modification.getRootNode().getDataAfter();
133 if (!isPortDown(flowConnector)) {
134 notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowConnector);
136 iiToDownFlowCapableNodeConnectors.put(nodeConnectorInstanceId, flowConnector);
141 private void processUpdatedConnector(final DataTreeModification<T> modification) {
142 final InstanceIdentifier<T> identifier = modification.getRootPath().getRootIdentifier();
143 InstanceIdentifier<NodeConnector> nodeConnectorInstanceId = identifier.firstIdentifierOf(NodeConnector.class);
144 if (compareIITail(identifier, II_TO_FLOW_CAPABLE_NODE_CONNECTOR)) {
145 FlowCapableNodeConnector flowConnector = (FlowCapableNodeConnector) modification.getRootNode().getDataAfter();
146 if (isPortDown(flowConnector)) {
147 notifyNodeConnectorDisappeared(nodeConnectorInstanceId);
149 notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowConnector);
151 } else if (compareIITail(identifier, II_TO_STATE)) {
152 FlowCapableNodeConnector flowNodeConnector = iiToDownFlowCapableNodeConnectors.get(nodeConnectorInstanceId);
153 if (flowNodeConnector != null) {
154 State state = (State) modification.getRootNode().getDataAfter();
155 if (!state.isLinkDown()) {
156 FlowCapableNodeConnectorBuilder flowCapableNodeConnectorBuilder =
157 new FlowCapableNodeConnectorBuilder(flowNodeConnector);
158 flowCapableNodeConnectorBuilder.setState(state);
159 notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowCapableNodeConnectorBuilder.build());
160 iiToDownFlowCapableNodeConnectors.remove(nodeConnectorInstanceId);
166 private void processRemovedConnector(final DataTreeModification<T> modification) {
167 final InstanceIdentifier<T> identifier = modification.getRootPath().getRootIdentifier();
168 if (compareIITail(identifier, II_TO_FLOW_CAPABLE_NODE_CONNECTOR)) {
169 InstanceIdentifier<NodeConnector> nodeConnectorInstanceId = identifier.firstIdentifierOf(NodeConnector.class);
170 notifyNodeConnectorDisappeared(nodeConnectorInstanceId);
174 private boolean compareIITail(final InstanceIdentifier<?> ii1, final InstanceIdentifier<?> ii2) {
175 return Iterables.getLast(ii1.getPathArguments()).equals(Iterables.getLast(ii2.getPathArguments()));
178 private static boolean isPortDown(final FlowCapableNodeConnector flowCapableNodeConnector) {
179 PortState portState = flowCapableNodeConnector.getState();
180 PortConfig portConfig = flowCapableNodeConnector.getConfiguration();
181 return portState != null && portState.isLinkDown()
182 || portConfig != null && portConfig.isPORTDOWN();
185 private void notifyNodeConnectorAppeared(final InstanceIdentifier<NodeConnector> nodeConnectorInstanceId,
186 final FlowCapableNodeConnector flowConnector) {
187 for (NodeConnectorEventsObserver observer : observers) {
188 observer.nodeConnectorAdded(nodeConnectorInstanceId, flowConnector);
192 private void notifyNodeConnectorDisappeared(final InstanceIdentifier<NodeConnector> nodeConnectorInstanceId) {
193 for (NodeConnectorEventsObserver observer : observers) {
194 observer.nodeConnectorRemoved(nodeConnectorInstanceId);