BUG 3548 - LLDP speaker doesn't start send LLDP packet on port up. 79/23079/1
authorJozef Gloncak <jgloncak@cisco.com>
Thu, 18 Jun 2015 12:10:52 +0000 (14:10 +0200)
committermichal rehak <mirehak@cisco.com>
Mon, 22 Jun 2015 12:18:04 +0000 (12:18 +0000)
Listener on changes on changes on State subtree was added.

If instance of FlowCapableNodeConnector with port down is received
in NodeConnectorInventoryEventTranslator then it is stored to local map.
When event port up event is received then stored instance is looked up
in map, state part is replaced (with port up information) and it is sent
to LLDP.

Change-Id: Ic989a88c06b2e266c63375bd19e3ed2c2b4d4c2d
Signed-off-by: Jozef Gloncak <jgloncak@cisco.com>
(cherry picked from commit 5865c58f43808e730fdb9dc310741663c304112d)

applications/lldp-speaker/src/main/java/org/opendaylight/openflowplugin/applications/lldpspeaker/NodeConnectorInventoryEventTranslator.java
applications/lldp-speaker/src/test/java/org/opendaylight/openflowplugin/applications/lldpspeaker/NodeConnectorInventoryEventTranslatorTest.java

index ed3028463b04fb6e837f5455ddcf80776071df56..71b3b3e6ce7c6c909e238e7b6fb77c16397aaa76 100644 (file)
@@ -8,6 +8,11 @@
 
 package org.opendaylight.openflowplugin.applications.lldpspeaker;
 
+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.HashMap;
 import com.google.common.collect.ImmutableSet;
 import java.util.Map;
 import java.util.Set;
@@ -34,26 +39,47 @@ import org.slf4j.LoggerFactory;
  * and update LLDPSpeaker and topology.
  */
 public class NodeConnectorInventoryEventTranslator implements DataChangeListener, AutoCloseable {
+    /**
+     *
+     */
+    private static final InstanceIdentifier<State> II_TO_STATE 
+        = InstanceIdentifier.builder(Nodes.class)
+            .child(Node.class)
+            .child(NodeConnector.class)
+            .augmentation(FlowCapableNodeConnector.class)
+            .child(State.class)
+            .build();
+
+    private static final InstanceIdentifier<FlowCapableNodeConnector> II_TO_FLOW_CAPABLE_NODE_CONNECTOR
+        = InstanceIdentifier.builder(Nodes.class)
+            .child(Node.class)
+            .child(NodeConnector.class)
+            .augmentation(FlowCapableNodeConnector.class)
+            .build();
+
     private static final Logger LOG = LoggerFactory.getLogger(NodeConnectorInventoryEventTranslator.class);
 
     private final ListenerRegistration<DataChangeListener> dataChangeListenerRegistration;
+    private final ListenerRegistration<DataChangeListener> 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,
-                InstanceIdentifier.builder(Nodes.class)
-                        .child(Node.class)
-                        .child(NodeConnector.class)
-                        .augmentation(FlowCapableNodeConnector.class)
-                        .build(),
+                II_TO_FLOW_CAPABLE_NODE_CONNECTOR,
                 this, AsyncDataBroker.DataChangeScope.BASE);
+        listenerOnPortStateRegistration = dataBroker.registerDataChangeListener(
+                LogicalDatastoreType.OPERATIONAL,
+                II_TO_STATE,
+                this, AsyncDataBroker.DataChangeScope.SUBTREE);
     }
 
     @Override
     public void close() {
         dataChangeListenerRegistration.close();
+        listenerOnPortStateRegistration.close();
     }
 
     @Override
@@ -65,10 +91,13 @@ public class NodeConnectorInventoryEventTranslator implements DataChangeListener
         for (Map.Entry<InstanceIdentifier<?>, DataObject> entry : change.getCreatedData().entrySet()) {
             InstanceIdentifier<NodeConnector> nodeConnectorInstanceId =
                     entry.getKey().firstIdentifierOf(NodeConnector.class);
-
-            FlowCapableNodeConnector flowConnector = (FlowCapableNodeConnector) entry.getValue();
-            if (!isPortDown(flowConnector)) {
-                notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowConnector);
+            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);
+                }
             }
         }
 
@@ -76,21 +105,46 @@ public class NodeConnectorInventoryEventTranslator implements DataChangeListener
         for (Map.Entry<InstanceIdentifier<?>, DataObject> entry : change.getUpdatedData().entrySet()) {
             InstanceIdentifier<NodeConnector> nodeConnectorInstanceId =
                     entry.getKey().firstIdentifierOf(NodeConnector.class);
-            FlowCapableNodeConnector flowConnector = (FlowCapableNodeConnector) entry.getValue();
-            if (isPortDown(flowConnector)) {
-                notifyNodeConnectorDisappeared(nodeConnectorInstanceId);
-            } else {
-                notifyNodeConnectorAppeared(nodeConnectorInstanceId, flowConnector);
+            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);
+                    }
+                }
             }
         }
 
         // Iterate over removed node connectors
         for (InstanceIdentifier<?> removed : change.getRemovedPaths()) {
-            InstanceIdentifier<NodeConnector> nodeConnectorInstanceId = removed.firstIdentifierOf(NodeConnector.class);
-            notifyNodeConnectorDisappeared(nodeConnectorInstanceId);
+            if (compareIITail(removed,II_TO_FLOW_CAPABLE_NODE_CONNECTOR)) {
+                InstanceIdentifier<NodeConnector> nodeConnectorInstanceId = removed.firstIdentifierOf(NodeConnector.class);
+                notifyNodeConnectorDisappeared(nodeConnectorInstanceId);
+            }
         }
     }
 
+    /**
+     * @param key
+     * @param iiToFlowCapableNodeConnector
+     * @return
+     */
+    private boolean compareIITail(InstanceIdentifier<?> ii1,
+            InstanceIdentifier<?> ii2) {
+        return Iterables.getLast(ii1.getPathArguments()).equals(Iterables.getLast(ii2.getPathArguments()));
+    }
+
     private static boolean isPortDown(FlowCapableNodeConnector flowCapableNodeConnector) {
         PortState portState = flowCapableNodeConnector.getState();
         PortConfig portConfig = flowCapableNodeConnector.getConfiguration();
index a5269220435e9c0357a71d957a6224fa62feaced..3426d29fcccdc1a4bfb6b147cf2dbb5aa830bdb5 100644 (file)
@@ -36,6 +36,7 @@ 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();
 
     @Mock DataBroker dataBroker;
@@ -48,6 +49,7 @@ public class NodeConnectorInventoryEventTranslatorTest {
 
     @Before
     public void setUp() {
+
         when(dataBroker.registerDataChangeListener(
                 any(LogicalDatastoreType.class),
                 any(InstanceIdentifier.class),
@@ -64,7 +66,7 @@ public class NodeConnectorInventoryEventTranslatorTest {
     @Test
     public void testNodeConnectorCreation() {
         // Setup dataChangedEvent to mock new port creation in inventory
-        dataChangedEvent.created.put(id, fcnc);
+        dataChangedEvent.created.put(iiToConnector, fcnc);
 
         // Invoke NodeConnectorInventoryEventTranslator and check result
         translator.onDataChanged(dataChangedEvent);
@@ -111,7 +113,7 @@ public class NodeConnectorInventoryEventTranslatorTest {
         FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector(true, false).build();
 
         // Setup dataChangedEvent to mock link down
-        dataChangedEvent.updated.put(id, fcnc);
+        dataChangedEvent.updated.put(iiToConnector, fcnc);
 
         // Invoke NodeConnectorInventoryEventTranslator and check result
         translator.onDataChanged(dataChangedEvent);
@@ -128,7 +130,7 @@ public class NodeConnectorInventoryEventTranslatorTest {
         FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector(false, true).build();
 
         // Setup dataChangedEvent to mock link down and administrative port down
-        dataChangedEvent.updated.put(id, fcnc);
+        dataChangedEvent.updated.put(iiToConnector, fcnc);
 
         // Invoke NodeConnectorInventoryEventTranslator and check result
         translator.onDataChanged(dataChangedEvent);
@@ -143,7 +145,7 @@ public class NodeConnectorInventoryEventTranslatorTest {
     @Test
     public void testNodeConnectorUpdateToUp() {
         // Setup dataChangedEvent to mock link up and administrative port up
-        dataChangedEvent.updated.put(id, fcnc);
+        dataChangedEvent.updated.put(iiToConnector, fcnc);
 
         // Invoke NodeConnectorInventoryEventTranslator and check result
         translator.onDataChanged(dataChangedEvent);
@@ -157,7 +159,7 @@ public class NodeConnectorInventoryEventTranslatorTest {
     @Test
     public void testNodeConnectorRemoval() {
         // Setup dataChangedEvent to mock node connector removal
-        dataChangedEvent.removed.add(id);
+        dataChangedEvent.removed.add(iiToConnector);
 
         // Invoke NodeConnectorInventoryEventTranslator and check result
         translator.onDataChanged(dataChangedEvent);
@@ -173,10 +175,11 @@ public class NodeConnectorInventoryEventTranslatorTest {
     public  void testMultipleObserversNotified() throws Exception {
         // 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(id, fcnc);
-        dataChangedEvent.removed.add(id2);
+        dataChangedEvent.created.put(iiToConnector, fcnc);
+        dataChangedEvent.removed.add(iiToConnector2);
 
         // Invoke onDataChanged and check that both observers notified
         translator.onDataChanged(dataChangedEvent);
@@ -197,7 +200,7 @@ public class NodeConnectorInventoryEventTranslatorTest {
         translator.close();
 
         // Verify that ListenerRegistration to DOM events
-        verify(dataChangeListenerRegistration).close();
+        verify(dataChangeListenerRegistration, times(2)).close();
     }
 
     static class MockDataChangedEvent implements AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> {