BUG 6179 - Turning off flow removed notification 63/41563/9
authormiroslav.macko <miroslav.macko@pantheon.tech>
Thu, 7 Jul 2016 07:06:22 +0000 (09:06 +0200)
committermiroslav.macko <miroslav.macko@pantheon.tech>
Tue, 19 Jul 2016 12:02:49 +0000 (14:02 +0200)
- created notification-flow-removed-off switch
in openflow-provider-config.yang with default value false
- added managed-properties to openflowplugin.xml

Change-Id: Id657e0b995a40eee3beda85794fbe81fc15c6875
Signed-off-by: miroslav.macko <miroslav.macko@pantheon.tech>
14 files changed:
features/pom.xml
features/src/main/features/features.xml
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OpenFlowPluginProvider.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceManager.java
openflowplugin-api/src/main/yang/openflow-provider-config.yang
openflowplugin-blueprint-config/pom.xml
openflowplugin-blueprint-config/src/main/resources/initial/openflowplugin.cfg [new file with mode: 0644]
openflowplugin-blueprint-config/src/main/resources/org/opendaylight/blueprint/openflowplugin.xml
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/OpenFlowPluginProviderFactoryImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/OpenFlowPluginProviderImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImpl.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImplTest.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImplTest.java

index 7bf9ea2bea2a970d181e415cc52d77cb35c611d1..e2eb7336e73d752cea3ca8113d4ca628f7fa83dc 100644 (file)
             <artifactId>openflowplugin-blueprint-config</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.openflowplugin</groupId>
+            <artifactId>openflowplugin-blueprint-config</artifactId>
+            <version>${project.version}</version>
+            <type>cfg</type>
+            <classifier>config</classifier>
+        </dependency>
 
         <dependency>
             <groupId>org.opendaylight.dlux</groupId>
index 4472d9510e6c10354e9981d0325c2bca11ca242f..8af29876c3588353ca84822619be65aff6c8da01 100644 (file)
@@ -49,6 +49,7 @@
         <bundle>mvn:org.opendaylight.openflowplugin/openflowplugin-extension-api/{{VERSION}}</bundle>
         <bundle>mvn:org.opendaylight.controller/liblldp/{{VERSION}}</bundle>
         <bundle>mvn:org.opendaylight.openflowplugin/openflowplugin-blueprint-config/{{VERSION}}</bundle>
+        <configfile finalname="etc/org.opendaylight.openflowplugin.cfg">mvn:org.opendaylight.openflowplugin/openflowplugin-blueprint-config/{{VERSION}}/cfg/config</configfile>
         <configfile finalname="etc/opendaylight/karaf/42-openflowplugin-Li.xml">mvn:org.opendaylight.openflowplugin/openflowplugin-controller-config/{{VERSION}}/xml/config-Li</configfile>
     </feature>
 
index 6173fb536f8e5285c827099106cb3d5dc1b9e4a9..8ad73aac1aa0c0d84e9b636f8d875dd2dab3a9cd 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.openflowplugin.api.openflow;
 
 import java.util.Collection;
+import java.util.Map;
 import org.opendaylight.controller.md.sal.binding.api.BindingService;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
@@ -73,4 +74,9 @@ public interface OpenFlowPluginProvider extends AutoCloseable, BindingService {
     void setBarrierInterval(long barrierTimeoutLimit);
 
     void setEchoReplyTimeout(long echoReplyTimeout);
+
+
+    void setNotificationFlowRemovedOff(boolean isNotificationFlowRemovedOff);
+
+    void update(Map<String,Object> props);
 }
index 55f68da8b7efe3689563127cd383cae4a10ff3a8..db07c8f8f8562d96f2db8ed18325c0521a277025 100644 (file)
@@ -72,5 +72,9 @@ public interface DeviceManager extends DeviceConnectedHandler, DeviceDisconnecte
      */
     void notifyDeviceValidListeners(final DeviceInfo deviceInfo, final boolean deviceValid);
 
+    void setIsNotificationFlowRemovedOff(boolean value);
+
+    boolean getIsNotificationFlowRemovedOff();
+
 }
 
index 2d180acbc0119a6c58feaac77c7848b9f789e8fa..49fd7c3aa68c78b56a83f4a702441a0986e06bb2 100644 (file)
@@ -82,5 +82,11 @@ module openflow-provider-config {
             type uint32;
             default 60;
         }
+
+        leaf notification-flow-removed-off {
+            description "Turning off flow removed notification";
+            type boolean;
+            default "false";
+        }
     }
 }
\ No newline at end of file
index 61dd36fe22ef95c0fd5359e2bfd119651ad95e9e..78e30d3715ad45dcdd750d0687679a5f23b7fb07 100644 (file)
            </instructions>
          </configuration>
        </plugin>
+       <plugin>
+           <groupId>org.codehaus.mojo</groupId>
+           <artifactId>build-helper-maven-plugin</artifactId>
+           <executions>
+               <execution>
+                   <id>attach-artifacts</id>
+                   <goals>
+                       <goal>attach-artifact</goal>
+                   </goals>
+                   <phase>package</phase>
+                   <configuration>
+                       <artifacts>
+                           <artifact>
+                               <file>${project.build.directory}/classes/initial/openflowplugin.cfg</file>
+                               <type>cfg</type>
+                               <classifier>config</classifier>
+                           </artifact>
+                       </artifacts>
+                   </configuration>
+               </execution>
+           </executions>
+       </plugin>
      </plugins>
    </build>
 </project>
diff --git a/openflowplugin-blueprint-config/src/main/resources/initial/openflowplugin.cfg b/openflowplugin-blueprint-config/src/main/resources/initial/openflowplugin.cfg
new file mode 100644 (file)
index 0000000..73d14d0
--- /dev/null
@@ -0,0 +1 @@
+notification-flow-removed-off=false
\ No newline at end of file
index db68c3b0184c9762fcc9c66f57500901915ca172..0eb0866c219da741602d73816b187bd1f727daed 100644 (file)
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
            xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+           xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
         odl:use-default-for-reference-types="true">
 
   <reference id="dataBroker" interface="org.opendaylight.controller.md.sal.binding.api.DataBroker" odl:type="pingpong"/>
@@ -73,6 +74,9 @@
         <ref component-id="legacySwitchConnProvider"/>
       </list>
     </argument>
+    <cm:managed-properties persistent-id="org.opendaylight.openflowplugin"
+                           update-strategy="component-managed"
+                           update-method="update"/>
   </bean>
 
   <service ref="openflowPluginProvider" odl:type="openflow-plugin-provider-impl">
index 0ad6129ce6a77b83a6a4db656b49432455102f3c..c216e439b7d7a8b84e848229152da23aa39b7b0b 100644 (file)
@@ -58,6 +58,7 @@ public class OpenFlowPluginProviderFactoryImpl implements OpenFlowPluginProvider
         openflowPluginProvider.setBarrierCountLimit(providerConfig.getBarrierCountLimit().getValue());
         openflowPluginProvider.setBarrierInterval(providerConfig.getBarrierIntervalTimeoutLimit().getValue());
         openflowPluginProvider.setEchoReplyTimeout(providerConfig.getEchoReplyTimeout().getValue());
+        openflowPluginProvider.setNotificationFlowRemovedOff(providerConfig.isNotificationFlowRemovedOff());
 
         openflowPluginProvider.initialize();
 
@@ -69,7 +70,8 @@ public class OpenFlowPluginProviderFactoryImpl implements OpenFlowPluginProvider
                 "EchoReplyTimeout:{}, " +
                 "ThreadPoolMinThreads:{}, " +
                 "ThreadPoolMaxThreads:{}, " +
-                "ThreadPoolTimeout:{}",
+                "ThreadPoolTimeout:{}, " +
+                "NotificationFlowRemovedOff:{}",
                 providerConfig.isIsStatisticsPollingOff(),
                 providerConfig.isSwitchFeaturesMandatory(),
                 providerConfig.getBarrierCountLimit().getValue(),
@@ -77,7 +79,8 @@ public class OpenFlowPluginProviderFactoryImpl implements OpenFlowPluginProvider
                 providerConfig.getEchoReplyTimeout().getValue(),
                 providerConfig.getThreadPoolMinThreads(),
                 providerConfig.getThreadPoolMaxThreads().getValue(),
-                providerConfig.getThreadPoolTimeout());
+                providerConfig.getThreadPoolTimeout(),
+                providerConfig.isNotificationFlowRemovedOff());
 
         return openflowPluginProvider;
     }
index 7d1fc5caea5677e9beba38cd415d6255284d2f65..70c4da81bd5bb4f74b1e7f19fdd58a6d53d59287 100644 (file)
@@ -17,6 +17,7 @@ import java.lang.management.ManagementFactory;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
@@ -87,6 +88,8 @@ public class OpenFlowPluginProviderImpl implements OpenFlowPluginProvider, OpenF
     private boolean switchFeaturesMandatory = false;
     private boolean isStatisticsPollingOff = false;
     private boolean isStatisticsRpcEnabled;
+    private boolean isNotificationFlowRemovedOff = false;
+    private Map<String,Object>  managedProperties;
 
     private final LifecycleConductor conductor;
     private final ThreadPoolExecutor threadPool;
@@ -170,6 +173,11 @@ public class OpenFlowPluginProviderImpl implements OpenFlowPluginProvider, OpenF
         this.echoReplyTimeout = echoReplyTimeout;
     }
 
+    @Override
+    public void setNotificationFlowRemovedOff(boolean isNotificationFlowRemovedOff) {
+        this.isNotificationFlowRemovedOff = isNotificationFlowRemovedOff;
+    }
+
 
     @Override
     public void setSwitchFeaturesMandatory(final boolean switchFeaturesMandatory) {
@@ -215,7 +223,8 @@ public class OpenFlowPluginProviderImpl implements OpenFlowPluginProvider, OpenF
                 switchFeaturesMandatory,
                 barrierInterval,
                 barrierCountLimit,
-                conductor);
+                conductor,
+                isNotificationFlowRemovedOff);
         ((ExtensionConverterProviderKeeper) conductor).setExtensionConverterProvider(extensionConverterManager);
         ((ExtensionConverterProviderKeeper) deviceManager).setExtensionConverterProvider(extensionConverterManager);
 
@@ -253,6 +262,16 @@ public class OpenFlowPluginProviderImpl implements OpenFlowPluginProvider, OpenF
         startSwitchConnections();
     }
 
+    @Override
+    public void update(Map<String,Object> props) {
+        LOG.debug("Update managed properties = {}", props.toString());
+        this.managedProperties = props;
+
+        if(deviceManager != null && props.containsKey("notification-flow-removed-off")) {
+            deviceManager.setIsNotificationFlowRemovedOff(Boolean.valueOf(props.get("notification-flow-removed-off").toString()));
+        }
+    }
+
     private static void registerMXBean(final MessageIntelligenceAgency messageIntelligenceAgency) {
         final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
         try {
index d15216cd0eaf28cb1398286d9fded4ff536db8e4..baf8c9e106f5e815725651a53c27c8278b6d99c0 100644 (file)
@@ -31,6 +31,7 @@ import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext
 import org.opendaylight.openflowplugin.api.openflow.connection.OutboundQueueProvider;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceManager;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
 import org.opendaylight.openflowplugin.api.openflow.device.MessageTranslator;
 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
@@ -129,18 +130,21 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi
     private final TranslatorLibrary translatorLibrary;
     private final ItemLifeCycleRegistry itemLifeCycleSourceRegistry;
     private ExtensionConverterProvider extensionConverterProvider;
+    private final DeviceManager deviceManager;
 
     private final DeviceInfo deviceInfo;
 
     private volatile CONTEXT_STATE contextState;
 
+
     @VisibleForTesting
     DeviceContextImpl(@Nonnull final ConnectionContext primaryConnectionContext,
                       @Nonnull final DeviceState deviceState,
                       @Nonnull final DataBroker dataBroker,
                       @Nonnull final LifecycleConductor conductor,
                       @Nonnull final OutboundQueueProvider outboundQueueProvider,
-                      @Nonnull final TranslatorLibrary translatorLibrary) {
+                      @Nonnull final TranslatorLibrary translatorLibrary,
+                      final DeviceManager manager) {
         this.primaryConnectionContext = Preconditions.checkNotNull(primaryConnectionContext);
         this.deviceState = Preconditions.checkNotNull(deviceState);
         this.dataBroker = Preconditions.checkNotNull(dataBroker);
@@ -153,7 +157,7 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi
         deviceGroupRegistry = new DeviceGroupRegistryImpl();
         deviceMeterRegistry = new DeviceMeterRegistryImpl();
         messageSpy = conductor.getMessageIntelligenceAgency();
-
+        this.deviceManager = Preconditions.checkNotNull(manager);
 
         packetInLimiter = new PacketInRateLimiter(primaryConnectionContext.getConnectionAdapter(),
                 /*initial*/ 1000, /*initial*/2000, messageSpy, REJECTED_DRAIN_FACTOR);
@@ -285,8 +289,13 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi
         //1. translate to general flow (table, priority, match, cookie)
         final org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemoved flowRemovedNotification =
                 flowRemovedTranslator.translate(flowRemoved, deviceInfo, null);
-        // Trigger off a notification
-        notificationPublishService.offerNotification(flowRemovedNotification);
+
+        if(!deviceManager.getIsNotificationFlowRemovedOff()) {
+            // Trigger off a notification
+            notificationPublishService.offerNotification(flowRemovedNotification);
+        } else if(LOG.isDebugEnabled()) {
+            LOG.debug("For nodeId={} isNotificationFlowRemovedOff={}", getDeviceInfo().getNodeId(), deviceManager.getIsNotificationFlowRemovedOff());
+        }
 
         final ItemLifecycleListener itemLifecycleListener = flowLifeCycleKeeper.getItemLifecycleListener();
         if (itemLifecycleListener != null) {
index fce73471c7327f91a309f3c8ebe97ead412a4911..362dbe171418d6dec88ea25dd2fee6e1c96c355f 100644 (file)
@@ -69,6 +69,7 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
 
     private final long globalNotificationQuota;
     private final boolean switchFeaturesMandatory;
+    private boolean isNotificationFlowRemovedOff;
 
     private final int spyRate = 10;
 
@@ -91,9 +92,10 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
     public DeviceManagerImpl(@Nonnull final DataBroker dataBroker,
                              final long globalNotificationQuota, final boolean switchFeaturesMandatory,
                              final long barrierInterval, final int barrierCountLimit,
-                             final LifecycleConductor lifecycleConductor) {
+                             final LifecycleConductor lifecycleConductor, boolean isNotificationFlowRemovedOff) {
         this.switchFeaturesMandatory = switchFeaturesMandatory;
         this.globalNotificationQuota = globalNotificationQuota;
+        this.isNotificationFlowRemovedOff = isNotificationFlowRemovedOff;
         this.dataBroker = Preconditions.checkNotNull(dataBroker);
         /* merge empty nodes to oper DS to predict any problems with missing parent for Node */
         final WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
@@ -174,7 +176,8 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
                 dataBroker,
                 conductor,
                 outboundQueueProvider,
-                translatorLibrary);
+                translatorLibrary,
+                this);
 
         Verify.verify(deviceContexts.putIfAbsent(deviceInfo, deviceContext) == null, "DeviceCtx still not closed.");
 
@@ -351,6 +354,16 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi
         }
     }
 
+    @Override
+    public void setIsNotificationFlowRemovedOff(boolean isNotificationFlowRemovedOff) {
+        this.isNotificationFlowRemovedOff = isNotificationFlowRemovedOff;
+    }
+
+    @Override
+    public boolean getIsNotificationFlowRemovedOff() {
+        return this.isNotificationFlowRemovedOff;
+    }
+
     private ListenableFuture<Void> onDeviceTakeClusterLeadership(final DeviceInfo deviceInfo) {
         LOG.trace("onDeviceTakeClusterLeadership for node: {}", deviceInfo.getNodeId());
         /* validation */
index f6298433c6b7afbd7aab4c60a029c3acee5c8237..0aed926c01e29f12234b9e4d6a1437ba38559a63 100644 (file)
@@ -33,6 +33,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InOrder;
+import org.mockito.Matchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.runners.MockitoJUnitRunner;
@@ -51,6 +52,7 @@ import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext
 import org.opendaylight.openflowplugin.api.openflow.connection.OutboundQueueProvider;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceManager;
 import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
 import org.opendaylight.openflowplugin.api.openflow.device.MessageTranslator;
 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
@@ -109,6 +111,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.Pa
 import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.Notification;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -170,6 +173,8 @@ public class DeviceContextImplTest {
     private LifecycleConductor lifecycleConductor;
     @Mock
     private DeviceInfo deviceInfo;
+    @Mock
+    private DeviceManager deviceManager;
 
     private InOrder inOrderDevState;
 
@@ -220,7 +225,7 @@ public class DeviceContextImplTest {
                 .thenReturn(messageTranslatorFlowRemoved);
         Mockito.when(lifecycleConductor.getMessageIntelligenceAgency()).thenReturn(messageIntelligenceAgency);
 
-        deviceContext = new DeviceContextImpl(connectionContext, deviceState, dataBroker, lifecycleConductor, outboundQueueProvider, translatorLibrary);
+        deviceContext = new DeviceContextImpl(connectionContext, deviceState, dataBroker, lifecycleConductor, outboundQueueProvider, translatorLibrary, deviceManager);
         deviceContextSpy = Mockito.spy(deviceContext);
 
         xid = new Xid(atomicLong.incrementAndGet());
@@ -231,17 +236,17 @@ public class DeviceContextImplTest {
 
     @Test(expected = NullPointerException.class)
     public void testDeviceContextImplConstructorNullDataBroker() throws Exception {
-        new DeviceContextImpl(connectionContext, deviceState, null, lifecycleConductor, outboundQueueProvider, translatorLibrary).close();
+        new DeviceContextImpl(connectionContext, deviceState, null, lifecycleConductor, outboundQueueProvider, translatorLibrary, deviceManager).close();
     }
 
     @Test(expected = NullPointerException.class)
     public void testDeviceContextImplConstructorNullDeviceState() throws Exception {
-        new DeviceContextImpl(connectionContext, null, dataBroker, lifecycleConductor, outboundQueueProvider, translatorLibrary).close();
+        new DeviceContextImpl(connectionContext, null, dataBroker, lifecycleConductor, outboundQueueProvider, translatorLibrary, deviceManager).close();
     }
 
     @Test(expected = NullPointerException.class)
     public void testDeviceContextImplConstructorNullTimer() throws Exception {
-        new DeviceContextImpl(null, deviceState, dataBroker, lifecycleConductor, outboundQueueProvider, translatorLibrary).close();
+        new DeviceContextImpl(null, deviceState, dataBroker, lifecycleConductor, outboundQueueProvider, translatorLibrary, deviceManager).close();
     }
 
     @Test
@@ -504,9 +509,18 @@ public class DeviceContextImplTest {
                 .child(Table.class, new TableKey((short) 0))
                 .child(Flow.class, new FlowKey(new FlowId("ut-ofp:f456")));
 
+        Mockito.when(deviceManager.getIsNotificationFlowRemovedOff()).thenReturn(true);
+
         deviceContext.setNotificationPublishService(mockedNotificationPublishService);
         deviceContext.processFlowRemovedMessage(flowRemovedBld.build());
+
         Mockito.verify(itemLifecycleListener).onRemoved(flowToBeRemovedPath);
+        Mockito.verify(mockedNotificationPublishService, Mockito.never()).offerNotification(Matchers.any(Notification.class));
+
+        Mockito.when(deviceManager.getIsNotificationFlowRemovedOff()).thenReturn(false);
+        deviceContext.processFlowRemovedMessage(flowRemovedBld.build());
+
+        Mockito.verify(mockedNotificationPublishService).offerNotification(Matchers.any(Notification.class));
     }
 
     @Test
index 1a7ddd1847b0247e0d136ab309d5c555e4f83d6a..e57c4a5d842cd8a386bdb2b1a2d7e66babd30b7f 100644 (file)
@@ -152,7 +152,7 @@ public class DeviceManagerImplTest {
         when(mockedWriteTransaction.submit()).thenReturn(mockedFuture);
 
         final DeviceManagerImpl deviceManager = new DeviceManagerImpl(mockedDataBroker,
-                TEST_VALUE_GLOBAL_NOTIFICATION_QUOTA, false, barrierIntervalNanos, barrierCountLimit, lifecycleConductor);
+                TEST_VALUE_GLOBAL_NOTIFICATION_QUOTA, false, barrierIntervalNanos, barrierCountLimit, lifecycleConductor, true);
 
         deviceManager.setDeviceInitializationPhaseHandler(deviceInitPhaseHandler);
         deviceManager.setDeviceTerminationPhaseHandler(deviceTerminationPhaseHandler);