</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>openflowplugin-extension-api</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>openflowplugin-extension-nicira</artifactId>
+ <artifactId>openflowplugin-blueprint-config</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>openflowplugin-extension-onf</artifactId>
+ <artifactId>drop-test-karaf</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>openflowjava-extension-nicira</artifactId>
+ <artifactId>openflowplugin-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>openflowjava-extension-nicira-api</artifactId>
+ <artifactId>test-common</artifactId>
<version>${project.version}</version>
</dependency>
+ <!-- models -->
<dependency>
<groupId>${project.groupId}.model</groupId>
<artifactId>model-flow-base</artifactId>
<artifactId>model-flow-statistics</artifactId>
<version>${project.version}</version>
</dependency>
+ <!-- extensions -->
<dependency>
- <groupId>${project.groupId}.applications</groupId>
- <artifactId>forwardingrules-manager</artifactId>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>openflowplugin-extension-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
- <groupId>${project.groupId}.applications</groupId>
- <artifactId>forwardingrules-sync</artifactId>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>openflowplugin-extension-nicira</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
- <groupId>${project.groupId}.applications</groupId>
- <artifactId>forwardingrules-sync</artifactId>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>openflowjava-extension-nicira-api</artifactId>
<version>${project.version}</version>
- <classifier>config</classifier>
- <type>xml</type>
</dependency>
<dependency>
- <groupId>${project.groupId}.applications</groupId>
- <artifactId>inventory-manager</artifactId>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>openflowjava-extension-nicira</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
- <groupId>${project.groupId}.applications</groupId>
- <artifactId>lldp-speaker</artifactId>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>openflowplugin-extension-onf</artifactId>
<version>${project.version}</version>
</dependency>
+ <!-- applications -->
<dependency>
<groupId>${project.groupId}.applications</groupId>
- <artifactId>statistics-manager</artifactId>
+ <artifactId>bulk-o-matic</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}.applications</groupId>
- <artifactId>table-miss-enforcer</artifactId>
+ <artifactId>forwardingrules-manager</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}.applications</groupId>
- <artifactId>topology-lldp-discovery</artifactId>
+ <artifactId>forwardingrules-sync</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}.applications</groupId>
- <artifactId>topology-manager</artifactId>
+ <artifactId>inventory-manager</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}.applications</groupId>
- <artifactId>of-switch-config-pusher</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>drop-test-karaf</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>${project.groupId}.legacy</groupId>
- <artifactId>sal-compatibility</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>openflowplugin-common</artifactId>
+ <artifactId>lldp-speaker</artifactId>
<version>${project.version}</version>
</dependency>
-
<dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>test-common</artifactId>
+ <groupId>${project.groupId}.applications</groupId>
+ <artifactId>statistics-manager</artifactId>
<version>${project.version}</version>
</dependency>
-
<dependency>
<groupId>${project.groupId}.applications</groupId>
<artifactId>table-miss-enforcer</artifactId>
<version>${project.version}</version>
- <type>xml</type>
- <classifier>config</classifier>
</dependency>
<dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>openflowplugin-blueprint-config</artifactId>
- <version>${project.version}</version>
- <type>cfg</type>
- <classifier>config</classifier>
- </dependency>
- <dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>openflowplugin-controller-config</artifactId>
+ <groupId>${project.groupId}.applications</groupId>
+ <artifactId>topology-lldp-discovery</artifactId>
<version>${project.version}</version>
- <type>xml</type>
- <classifier>config-He</classifier>
</dependency>
<dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>openflowplugin-controller-config</artifactId>
+ <groupId>${project.groupId}.applications</groupId>
+ <artifactId>topology-manager</artifactId>
<version>${project.version}</version>
- <type>xml</type>
- <classifier>config-Li</classifier>
</dependency>
<dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>openflowplugin-controller-config</artifactId>
+ <groupId>${project.groupId}.applications</groupId>
+ <artifactId>of-switch-config-pusher</artifactId>
<version>${project.version}</version>
- <type>xml</type>
- <classifier>configmsgspy</classifier>
</dependency>
<dependency>
- <groupId>${project.groupId}</groupId>
- <artifactId>openflowplugin-extension-nicira-config</artifactId>
+ <groupId>${project.groupId}.applications</groupId>
+ <artifactId>notification-supplier</artifactId>
<version>${project.version}</version>
- <type>xml</type>
- <classifier>config</classifier>
</dependency>
+ <!-- config files -->
<dependency>
<groupId>${project.groupId}</groupId>
- <artifactId>drop-test-karaf</artifactId>
+ <artifactId>openflowplugin-blueprint-config</artifactId>
<version>${project.version}</version>
- <type>xml</type>
+ <type>cfg</type>
<classifier>config</classifier>
</dependency>
-
+ <!-- features -->
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>features-openflowplugin</artifactId>
<classifier>features</classifier>
<type>xml</type>
</dependency>
- <dependency>
- <groupId>${project.groupId}.applications</groupId>
- <artifactId>bulk-o-matic</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>${project.groupId}.applications</groupId>
- <artifactId>bulk-o-matic</artifactId>
- <version>${project.version}</version>
- <type>xml</type>
- <classifier>config</classifier>
- </dependency>
- <dependency>
- <groupId>${project.groupId}.applications</groupId>
- <artifactId>notification-supplier</artifactId>
- <version>${project.version}</version>
- <type>xml</type>
- <classifier>config</classifier>
- </dependency>
- <dependency>
- <groupId>${project.groupId}.applications</groupId>
- <artifactId>notification-supplier</artifactId>
- <version>${project.version}</version>
- </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>odl-openflowplugin-flow-services-rest</artifactId>
<type>xml</type>
<version>${project.version}</version>
</dependency>
-
</dependencies>
</dependencyManagement>
</project>
<dependency>
<groupId>org.opendaylight.openflowplugin</groupId>
<artifactId>openflowplugin-blueprint-config</artifactId>
- <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.openflowjava</groupId>
*/
public interface OFPContext extends AutoCloseable, ClusterLifecycleSupervisor, ClusterInitializationPhaseHandler {
-
/**
* Context state.
*/
TERMINATION
}
- /**
- * Get actual context state.
- * @return actual context state
- */
- ContextState getState();
-
/**
* About to stop services in cluster not master anymore or going down.
* @return Future most of services need time to be closed.
import com.google.common.util.concurrent.ListenableFuture;
import io.netty.util.Timeout;
-import java.math.BigInteger;
import java.util.List;
import javax.annotation.Nonnull;
import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
RequestContextStack,
ContextChainStateListener {
- /**
- * Method close all auxiliary connections and primary connection.
- */
- void shutdownConnection();
-
- /**
- * Method add auxiliary connection contexts to this context representing single device connection.
- * @param connectionContext new connection context
- */
- void addAuxiliaryConnectionContext(ConnectionContext connectionContext);
-
- /**
- * Method removes auxiliary connection context from this context representing single device connection.
- * @param connectionContext connection which need to be removed
- */
- void removeAuxiliaryConnectionContext(ConnectionContext connectionContext);
-
/**
* Method provides state of device represented by this device context.
*
*/
DeviceState getDeviceState();
- /**
- * Method has to close TxManager ASAP we are notified about Closed Connection.
- * @return sync. future for Slave and MD-SAL completition for Master
- */
- ListenableFuture<Void> shuttingDownDataStoreTransactions();
-
/**
* Getter.
* @return current devices connection context
*/
ConnectionContext getPrimaryConnectionContext();
- /**
- * Getter.
- * @return current devices auxiliary connection contexts
- */
- ConnectionContext getAuxiliaryConnectionContexts(BigInteger cookie);
-
-
/**
* Getter.
* @return translator library
void setSwitchFeaturesMandatory(boolean switchFeaturesMandatory);
- boolean isSkipTableFeatures();
-
/**
* Setter for sal role service.
* @param salRoleService Role Service
void setBarrierInterval(long barrierTimeoutLimit);
CheckedFuture<Void, TransactionCommitFailedException> removeDeviceFromOperationalDS(
- DeviceInfo deviceInfo);
-
- CheckedFuture<Void, TransactionCommitFailedException> removeDeviceFromOperationalDS(
- KeyedInstanceIdentifier<Node, NodeKey> ii);
+ @Nonnull KeyedInstanceIdentifier<Node, NodeKey> ii);
DeviceContext createContext(@Nonnull ConnectionContext connectionContext);
- long getBarrierIntervalNanos();
- int getBarrierCountLimit();
+ void sendNodeAddedNotification(
+ @Nonnull KeyedInstanceIdentifier<Node, NodeKey> instanceIdentifier);
- void sendNodeAddedNotification(@Nonnull DeviceInfo deviceInfo);
+ void sendNodeRemovedNotification(
+ @Nonnull KeyedInstanceIdentifier<Node, NodeKey> instanceIdentifier);
}
*/
boolean isMastered(@Nonnull ContextChainMastershipState mastershipState);
- /**
- * Device need to be in state SLAVE or MASTER.
- * @return false if in undefined state
- */
- boolean hasState();
-
/**
* Add new auxiliary connection if primary is ok.
* @param connectionContext new connection to the device.
*/
package org.opendaylight.openflowplugin.api.openflow.lifecycle;
-import com.google.common.util.concurrent.ListenableFuture;
+import javax.annotation.Nonnull;
import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
* Called if connection needs to be destroyed.
* @param deviceInfo {@link DeviceInfo}
*/
- ListenableFuture<Void> destroyContextChain(DeviceInfo deviceInfo);
+ void destroyContextChain(DeviceInfo deviceInfo);
/**
* Provider is needed to register cluster singleton service.
* Register EOS listener.
* @param entityOwnershipService EOS services
*/
- void changeEntityOwnershipService(EntityOwnershipService entityOwnershipService);
+ void changeEntityOwnershipService(@Nonnull EntityOwnershipService entityOwnershipService);
@Override
void close() throws Exception;
-}
+}
\ No newline at end of file
* Initial flow registry fill is done.
*/
INITIAL_FLOW_REGISTRY_FILL,
+ /**
+ * Registration of RPC services is done.
+ */
+ RPC_REGISTRATION,
/**
* Check mastership.
*/
CHECK
-
}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
-
- This program and the accompanying materials are made available under the
- terms of the Eclipse Public License v1.0 which accompanies this distribution,
- and is available at http://www.eclipse.org/legal/epl-v10.html
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.opendaylight.openflowplugin</groupId>
- <artifactId>openflowplugin-parent</artifactId>
- <version>0.5.0-SNAPSHOT</version>
- <relativePath>../parent</relativePath>
- </parent>
-
- <artifactId>openflowplugin-controller-config</artifactId>
- <description>Controller Configuration files for openflowplugin + openflowjava couple</description>
- <packaging>jar</packaging>
- <build>
- <plugins>
- <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/42-openflowplugin.xml</file>
- <type>xml</type>
- <classifier>config-He</classifier>
- </artifact>
- </artifacts>
- </configuration>
- </execution>
- <execution>
- <id>attach-artifacts-ofp-cfg</id>
- <goals>
- <goal>attach-artifact</goal>
- </goals>
- <phase>package</phase>
- <configuration>
- <artifacts>
- <artifact>
- <file>${project.build.directory}/classes/initial/42-openflowplugin-new.xml</file>
- <type>xml</type>
- <classifier>config-Li</classifier>
- </artifact>
- </artifacts>
- </configuration>
- </execution>
- <execution>
- <id>attach-artifacts-msgspy</id>
- <goals>
- <goal>attach-artifact</goal>
- </goals>
- <phase>package</phase>
- <configuration>
- <artifacts>
- <artifact>
- <file>${project.build.directory}/classes/initial/43-msg-spy.xml</file>
- <type>xml</type>
- <classifier>configmsgspy</classifier>
- </artifact>
- </artifacts>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
-</project>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- vi: set et smarttab sw=4 tabstop=4: -->
-<!--
-Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
-
-This program and the accompanying materials are made available under the
-terms of the Eclipse Public License v1.0 which accompanies this distribution,
-and is available at http://www.eclipse.org/legal/epl-v10.html
-
-NOTE: This file is deprecated as wiring is now done via blueprint. This file is kept for
- backwards compatibility. Runtime modifications are not honored.
--->
-<snapshot>
- <required-capabilities>
- <!-- openflowjava -->
- <capability>
- urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider:impl?module=openflow-switch-connection-provider-impl&revision=2014-03-28
- </capability>
- <capability>
- urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider?module=openflow-switch-connection-provider&revision=2014-03-28
- </capability>
- <!-- openflowplugin -->
- <capability>urn:opendaylight:params:xml:ns:yang:config:openflow:plugin:impl?module=openflow-plugin-provider-impl&revision=2015-03-27</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:openflow:api?module=openflow-provider&revision=2015-03-31</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:openflowplugin:extension:api?module=openflowplugin-extension-registry&revision=2015-04-25</capability>
- <!-- binding-broker-impl - provided -->
- </required-capabilities>
-
- <configuration>
-
- <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
- <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <!-- default OF-switch-connection-provider (port 6633) -->
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider:impl">
- prefix:openflow-switch-connection-provider-impl
- </type>
- <name>openflow-switch-connection-provider-default-impl</name>
- <port>6633</port>
- <!-- Possible transport-protocol options: TCP, TLS, UDP -->
- <transport-protocol>TCP</transport-protocol>
- <switch-idle-timeout>15000</switch-idle-timeout>
- </module>
- <!-- default OF-switch-connection-provider (port 6653) -->
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider:impl">
- prefix:openflow-switch-connection-provider-impl
- </type>
- <name>openflow-switch-connection-provider-legacy-impl</name>
- <port>6653</port>
- <!-- Possible transport-protocol options: TCP, TLS, UDP -->
- <transport-protocol>TCP</transport-protocol>
- <switch-idle-timeout>15000</switch-idle-timeout>
- </module>
-
-
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:config:openflow:plugin:impl">
- prefix:openflow-plugin-provider-impl
- </type>
- <name>openflow-plugin-provider-impl</name>
-
- <openflow-switch-connection-provider>
- <type xmlns:ofSwitch="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider">ofSwitch:openflow-switch-connection-provider</type>
- <name>openflow-switch-connection-provider-default</name>
- </openflow-switch-connection-provider>
- <openflow-switch-connection-provider>
- <type xmlns:ofSwitch="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider">ofSwitch:openflow-switch-connection-provider</type>
- <name>openflow-switch-connection-provider-legacy</name>
- </openflow-switch-connection-provider>
-
- <data-broker>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
- <name>pingpong-binding-data-broker</name>
- </data-broker>
- <rpc-registry>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
- <name>binding-rpc-broker</name>
- </rpc-registry>
- <notification-adapter>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-new-notification-service</type>
- <name>binding-notification-adapter</name>
- </notification-adapter>
- <notification-publish-adapter>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-new-notification-publish-service</type>
- <name>binding-notification-publish-adapter</name>
- </notification-publish-adapter>
- <entity-ownership-service>
- <type xmlns:entity-ownership="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">entity-ownership:entity-ownership-service</type>
- <name>entity-ownership-service</name>
- </entity-ownership-service>
- <rpc-requests-quota>20000</rpc-requests-quota>
- <switch-features-mandatory>false</switch-features-mandatory>
- <global-notification-quota>64000</global-notification-quota>
- <is-statistics-polling-on>true</is-statistics-polling-on>
- <barrier-interval-timeout-limit>500</barrier-interval-timeout-limit>
- <barrier-count-limit>25600</barrier-count-limit>
- <echo-reply-timeout>2000</echo-reply-timeout>
- </module>
- </modules>
-
- <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <service>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider">prefix:openflow-switch-connection-provider</type>
- <instance>
- <name>openflow-switch-connection-provider-default</name>
- <provider>/modules/module[type='openflow-switch-connection-provider-impl'][name='openflow-switch-connection-provider-default-impl']</provider>
- </instance>
- <instance>
- <name>openflow-switch-connection-provider-legacy</name>
- <provider>/modules/module[type='openflow-switch-connection-provider-impl'][name='openflow-switch-connection-provider-legacy-impl']</provider>
- </instance>
- </service>
- <service>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:api">
- prefix:openflow-provider
- </type>
- <instance>
- <name>openflow-provider</name>
- <provider>
- /modules/module[type='openflow-plugin-provider-impl'][name='openflow-plugin-provider-impl']
- </provider>
- </instance>
- </service>
- <service>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflowplugin:extension:api">prefix:openflow-extension-registry-provider</type>
- <instance>
- <name>openflow-ext-provider</name>
- <provider>
- /modules/module[type='openflow-plugin-provider-impl'][name='openflow-plugin-provider-impl']
- </provider>
- </instance>
- </service>
- </services>
- </data>
-
- </configuration>
-</snapshot>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- vi: set et smarttab sw=4 tabstop=4: -->
-<!--
-Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
-
-This program and the accompanying materials are made available under the
-terms of the Eclipse Public License v1.0 which accompanies this distribution,
-and is available at http://www.eclipse.org/legal/epl-v10.html
--->
-<snapshot>
- <required-capabilities>
- <!-- openflowjava -->
- <capability>urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider:impl?module=openflow-switch-connection-provider-impl&revision=2014-03-28</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider?module=openflow-switch-connection-provider&revision=2014-03-28</capability>
- <!-- openflowplugin -->
- <capability>urn:opendaylight:params:xml:ns:yang:openflow:common:config:impl?module=openflow-provider-impl&revision=2014-03-26</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:openflow:common:config?module=openflow-provider&revision=2014-03-26</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:openflowplugin:extension:api?module=openflowplugin-extension-registry&revision=2015-04-25</capability>
- <!-- binding-broker-impl - provided -->
- </required-capabilities>
-
- <configuration>
-
- <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
- <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <!-- default OF-switch-connection-provider (port 6633) -->
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider:impl">prefix:openflow-switch-connection-provider-impl</type>
- <name>openflow-switch-connection-provider-default-impl</name>
- <port>6633</port>
-<!-- Possible transport-protocol options: TCP, TLS, UDP -->
- <transport-protocol>TCP</transport-protocol>
- <switch-idle-timeout>15000</switch-idle-timeout>
-<!-- Exemplary TLS configuration:
- - uncomment the <tls> tag
- - copy exemplary-switch-privkey.pem, exemplary-switch-cert.pem and exemplary-cacert.pem
- files into your virtual machine
- - set VM encryption options to use copied keys
- - start communication
- Please visit OpenflowPlugin or Openflow Protocol Library#Documentation wiki pages
- for detailed information regarding TLS -->
-<!-- <tls>
- <keystore>/exemplary-ctlKeystore</keystore>
- <keystore-type>JKS</keystore-type>
- <keystore-path-type>CLASSPATH</keystore-path-type>
- <keystore-password>opendaylight</keystore-password>
- <truststore>/exemplary-ctlTrustStore</truststore>
- <truststore-type>JKS</truststore-type>
- <truststore-path-type>CLASSPATH</truststore-path-type>
- <truststore-password>opendaylight</truststore-password>
- <certificate-password>opendaylight</certificate-password>
- </tls> -->
-<!-- Exemplary thread model configuration. Uncomment <threads> tag below to adjust default thread model -->
-<!-- <threads>
- <boss-threads>2</boss-threads>
- <worker-threads>8</worker-threads>
- </threads> -->
- </module>
- <!-- default OF-switch-connection-provider (port 6653) -->
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider:impl">prefix:openflow-switch-connection-provider-impl</type>
- <name>openflow-switch-connection-provider-legacy-impl</name>
- <port>6653</port>
-<!-- Possible transport-protocol options: TCP, TLS, UDP -->
- <transport-protocol>TCP</transport-protocol>
- <switch-idle-timeout>15000</switch-idle-timeout>
-<!-- Exemplary TLS configuration:
- - uncomment the <tls> tag
- - copy exemplary-switch-privkey.pem, exemplary-switch-cert.pem and exemplary-cacert.pem
- files into your virtual machine
- - set VM encryption options to use copied keys
- - start communication
- Please visit OpenflowPlugin or Openflow Protocol Library#Documentation wiki pages
- for detailed information regarding TLS -->
-<!-- <tls>
- <keystore>/exemplary-ctlKeystore</keystore>
- <keystore-type>JKS</keystore-type>
- <keystore-path-type>CLASSPATH</keystore-path-type>
- <keystore-password>opendaylight</keystore-password>
- <truststore>/exemplary-ctlTrustStore</truststore>
- <truststore-type>JKS</truststore-type>
- <truststore-path-type>CLASSPATH</truststore-path-type>
- <truststore-password>opendaylight</truststore-password>
- <certificate-password>opendaylight</certificate-password>
- </tls> -->
-<!-- Exemplary thread model configuration. Uncomment <threads> tag below to adjust default thread model -->
-<!-- <threads>
- <boss-threads>2</boss-threads>
- <worker-threads>8</worker-threads>
- </threads> -->
- </module>
-
-
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:common:config:impl">prefix:openflow-provider-impl</type>
- <name>openflow-provider-impl</name>
-
- <openflow-switch-connection-provider>
- <type xmlns:ofSwitch="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider">ofSwitch:openflow-switch-connection-provider</type>
- <name>openflow-switch-connection-provider-default</name>
- </openflow-switch-connection-provider>
- <openflow-switch-connection-provider>
- <type xmlns:ofSwitch="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider">ofSwitch:openflow-switch-connection-provider</type>
- <name>openflow-switch-connection-provider-legacy</name>
- </openflow-switch-connection-provider>
-
- <data-broker>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
- <name>pingpong-binding-data-broker</name>
- </data-broker>
- <rpc-registry>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
- <name>binding-rpc-broker</name>
- </rpc-registry>
- <notification-service>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
- <name>binding-notification-broker</name>
- </notification-service>
- <ownership-service>
- <type xmlns:entity-ownership="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">entity-ownership:entity-ownership-service</type>
- <name>entity-ownership-service</name>
- </ownership-service>
-
- <!-- openflowplugin configuraion -->
- <skip-table-features>false</skip-table-features>
-
- </module>
- </modules>
-
- <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <service>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider">prefix:openflow-switch-connection-provider</type>
- <instance>
- <name>openflow-switch-connection-provider-default</name>
- <provider>/modules/module[type='openflow-switch-connection-provider-impl'][name='openflow-switch-connection-provider-default-impl']</provider>
- </instance>
- <instance>
- <name>openflow-switch-connection-provider-legacy</name>
- <provider>/modules/module[type='openflow-switch-connection-provider-impl'][name='openflow-switch-connection-provider-legacy-impl']</provider>
- </instance>
- </service>
-
- <service>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflow:common:config">prefix:openflow-provider</type>
- <instance>
- <name>openflow-provider</name>
- <provider>/modules/module[type='openflow-provider-impl'][name='openflow-provider-impl']</provider>
- </instance>
- </service>
-
- <service>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:openflowplugin:extension:api">prefix:openflow-extension-registry-provider</type>
- <instance>
- <name>openflow-ext-provider</name>
- <provider>/modules/module[type='openflow-provider-impl'][name='openflow-provider-impl']</provider>
- </instance>
- </service>
- </services>
- </data>
-
- </configuration>
-</snapshot>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- vi: set et smarttab sw=4 tabstop=4: -->
-<!--
-Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
-
-This program and the accompanying materials are made available under the
-terms of the Eclipse Public License v1.0 which accompanies this distribution,
-and is available at http://www.eclipse.org/legal/epl-v10.html
--->
-<snapshot>
- <required-capabilities>
- <!-- openflowjava -->
- <capability>urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider:impl?module=openflow-switch-connection-provider-impl&revision=2014-03-28</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:openflow:switch:connection:provider?module=openflow-switch-connection-provider&revision=2014-03-28</capability>
- <!-- openflowplugin -->
- <capability>urn:opendaylight:params:xml:ns:yang:openflow:common:config:impl?module=openflow-provider-impl&revision=2014-03-26</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:openflow:common:config?module=openflow-provider&revision=2014-03-26</capability>
- <!-- binding-broker-impl - provided -->
- </required-capabilities>
-
- <configuration>
-
- <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
- <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <module>
- <type xmlns:msgspy="urn:opendaylight:params:xml:ns:yang:openflow:common:config:impl">msgspy:msg-spy-service-impl</type>
- <name>msg-spy-service-impl</name>
-
- <openflow-plugin-provider>
- <type xmlns:opfprov="urn:opendaylight:params:xml:ns:yang:openflow:common:config">opfprov:openflow-provider</type>
- <name>openflow-provider</name>
- </openflow-plugin-provider>
- </module>
- </modules>
-
- <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
- <service>
- <type xmlns:msgspy="urn:opendaylight:params:xml:ns:yang:openflow:common:config:impl">msgspy:msg-spy-service</type>
- <instance>
- <name>msg-spy-service</name>
- <provider>/modules/module[type='msg-spy-service-impl'][name='msg-spy-service-impl']</provider>
- </instance>
- </service>
- </services>
- </data>
-
- </configuration>
-</snapshot>
</instructions>
</configuration>
</plugin>
- <plugin>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-maven-plugin</artifactId>
- <executions>
- <execution>
- <goals>
- <goal>generate-sources</goal>
- </goals>
- <configuration>
- <codeGenerators>
- <generator>
- <codeGeneratorClass>
- org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
- </codeGeneratorClass>
- <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>
- <additionalConfiguration>
- <namespaceToPackage1>
- urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
- </namespaceToPackage1>
- </additionalConfiguration>
- </generator>
- <generator>
- <codeGeneratorClass>
- org.opendaylight.mdsal.binding.maven.api.gen.plugin.CodeGeneratorImpl
- </codeGeneratorClass>
- <outputBaseDir>${project.build.directory}/generated-sources/sal</outputBaseDir>
- </generator>
- <generator>
- <codeGeneratorClass>org.opendaylight.mdsal.binding.yang.unified.doc.generator.maven.DocumentationGeneratorImpl</codeGeneratorClass>
- <outputBaseDir>${project.build.directory}/site/models</outputBaseDir>
- </generator>
- </codeGenerators>
- <inspectDependencies>true</inspectDependencies>
- </configuration>
- </execution>
- </executions>
- <dependencies>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>yang-jmx-generator-plugin</artifactId>
- <version>${config.version}</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.mdsal</groupId>
- <artifactId>maven-sal-api-gen-plugin</artifactId>
- <version>${mdsal.model.version}</version>
- <type>jar</type>
- </dependency>
- </dependencies>
- </plugin>
</plugins>
</build>
<dependencies>
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timer;
import java.lang.management.ManagementFactory;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
private final Collection<SwitchConnectionProvider> switchConnectionProviders;
private final DeviceInitializerProvider deviceInitializerProvider;
private final ConvertorManager convertorManager;
- private final ContextChainHolder contextChainHolder;
private final RpcProviderRegistry rpcProviderRegistry;
private final ClusterSingletonServiceProvider singletonServicesProvider;
+ private final EntityOwnershipService entityOwnershipService;
+ private ContextChainHolder contextChainHolder;
private int rpcRequestsQuota;
private long globalNotificationQuota;
private long barrierInterval;
this.rpcProviderRegistry = rpcProviderRegistry;
this.notificationPublishService = notificationPublishService;
this.singletonServicesProvider = singletonServiceProvider;
+ this.entityOwnershipService = entityOwnershipService;
convertorManager = ConvertorManagerFactory.createDefaultManager();
- contextChainHolder = new ContextChainHolderImpl(hashedWheelTimer);
- contextChainHolder.changeEntityOwnershipService(entityOwnershipService);
extensionConverterManager = new ExtensionConverterManagerImpl();
deviceInitializerProvider = DeviceInitializerProviderFactory.createDefaultProvider();
}
});
}
- private void shutdownSwitchConnections() {
- Futures.addCallback(Futures.allAsList(switchConnectionProviders.stream().map(switchConnectionProvider -> {
+ private ListenableFuture<List<Boolean>> shutdownSwitchConnections() {
+ final ListenableFuture<List<Boolean>> listListenableFuture = Futures.allAsList(switchConnectionProviders.stream().map(switchConnectionProvider -> {
// Revert deserializers to their original state
if (useSingleLayerSerialization) {
DeserializerInjector.revertDeserializers(switchConnectionProvider);
// Shutdown switch connection provider
return switchConnectionProvider.shutdown();
- }).collect(Collectors.toSet())), new FutureCallback<List<Boolean>>() {
+ }).collect(Collectors.toSet()));
+
+ Futures.addCallback(listListenableFuture, new FutureCallback<List<Boolean>>() {
@Override
public void onSuccess(final List<Boolean> result) {
LOG.info("All switchConnectionProviders were successfully shut down ({}).", result.size());
LOG.warn("Some switchConnectionProviders failed to shutdown.", throwable);
}
});
+
+ return listListenableFuture;
}
@Override
Preconditions.checkNotNull(threadPoolTimeout),
TimeUnit.SECONDS, new SynchronousQueue<>(), POOL_NAME);
+
+ contextChainHolder = new ContextChainHolderImpl(hashedWheelTimer, threadPool);
+ contextChainHolder.changeEntityOwnershipService(entityOwnershipService);
+
connectionManager = new ConnectionManagerImpl(threadPool);
connectionManager.setEchoReplyTimeout(echoReplyTimeout);
}
@Override
- public void close() throws Exception {
+ public void close() {
initialized = false;
+
+ try {
+ shutdownSwitchConnections().get(10, TimeUnit.SECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ LOG.warn("Failed to shut down switch connections in time {}s, error: {}", 10, e);
+ }
+
gracefulShutdown(contextChainHolder);
gracefulShutdown(deviceManager);
gracefulShutdown(rpcManager);
gracefulShutdown(statisticsManager);
gracefulShutdown(threadPool);
gracefulShutdown(hashedWheelTimer);
- shutdownSwitchConnections();
unregisterMXBean(MESSAGE_INTELLIGENCE_AGENCY_MX_BEAN_NAME);
}
}
try {
- threadPoolExecutor.shutdown();
+ threadPoolExecutor.shutdownNow();
} catch (Exception e) {
LOG.warn("Failed to shutdown {} gracefully.", threadPoolExecutor);
}
package org.opendaylight.openflowplugin.impl.connection;
+import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import java.math.BigInteger;
-import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueue;
@Override
public void closeConnection(final boolean propagate) {
- if (Objects.isNull(nodeId)){
- SessionStatistics.countEvent(connectionAdapter.getRemoteAddress().toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_OFP);
- } else {
- SessionStatistics.countEvent(nodeId.toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_OFP);
- }
- final BigInteger datapathId = Objects.nonNull(featuresReply) ? featuresReply.getDatapathId() : BigInteger.ZERO;
- if (LOG.isDebugEnabled()) {
- LOG.debug("Actively closing connection: {}, datapathId: {}",
- connectionAdapter.getRemoteAddress(), datapathId);
- }
- connectionState = ConnectionContext.CONNECTION_STATE.RIP;
-
- portStatusMessages.clear();
- unregisterOutboundQueue();
- closeHandshakeContext();
-
- if (getConnectionAdapter().isAlive()) {
- getConnectionAdapter().disconnect();
- }
-
- if (propagate) {
- propagateDeviceDisconnectedEvent();
- }
+ disconnectDevice(propagate, true);
}
private void closeHandshakeContext() {
@Override
public void onConnectionClosed() {
- connectionState = ConnectionContext.CONNECTION_STATE.RIP;
+ disconnectDevice(true, false);
+ }
- if (null == nodeId){
- SessionStatistics.countEvent(connectionAdapter.getRemoteAddress().toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_DEVICE);
- } else {
- SessionStatistics.countEvent(nodeId.toString(), SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_DEVICE);
+ private void disconnectDevice(final boolean propagate,
+ final boolean forced) {
+ final String device = Objects.nonNull(nodeId) ? nodeId.getValue() : getConnectionAdapter().getRemoteAddress().toString();
+ final short auxiliaryId = Optional
+ .ofNullable(getFeatures())
+ .flatMap(features -> Optional
+ .ofNullable(features.getAuxiliaryId()))
+ .orElse((short) 0);
+
+ if (connectionState == CONNECTION_STATE.RIP) {
+ LOG.debug("Connection for device {} with auxiliary ID {} is already {}, so skipping closing.",
+ device, auxiliaryId, getConnectionState());
+ return;
}
- final InetSocketAddress remoteAddress = connectionAdapter.getRemoteAddress();
- final Short auxiliaryId;
- if (null != getFeatures() && null != getFeatures().getAuxiliaryId()) {
- auxiliaryId = getFeatures().getAuxiliaryId();
- } else {
- auxiliaryId = 0;
- }
+ SessionStatistics.countEvent(device, forced
+ ? SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_OFP
+ : SessionStatistics.ConnectionStatus.CONNECTION_DISCONNECTED_BY_DEVICE);
+
+ connectionState = ConnectionContext.CONNECTION_STATE.RIP;
- LOG.debug("disconnecting: node={}|auxId={}|connection state = {}",
- remoteAddress,
+ LOG.debug("{}: device={} | auxiliaryId={} | connectionState={}",
+ forced ? "Actively closing connection" : "Disconnecting",
+ device,
auxiliaryId,
getConnectionState());
portStatusMessages.clear();
unregisterOutboundQueue();
closeHandshakeContext();
- propagateDeviceDisconnectedEvent();
+
+ if (forced && getConnectionAdapter().isAlive()) {
+ getConnectionAdapter().disconnect();
+ }
+
+ if (propagate) {
+ propagateDeviceDisconnectedEvent();
+ }
}
private void propagateDeviceDisconnectedEvent() {
@Override
public void handlePortStatusMessage(final PortStatusMessage portStatusMessage) {
- if (Objects.isNull(deviceInfo)) {
- LOG.debug("NOOP: Port-status message during handshake phase not supported: {}", portStatusMessage);
- return;
- }
+ LOG.info("Received early port status message for node {} with reason {} and state {}",
+ nodeId.getValue(),
+ portStatusMessage.getReason(),
+ MoreObjects.firstNonNull(portStatusMessage.getState(), portStatusMessage.getStateV10()));
- LOG.debug("Handling alien port status message {} for node {}", portStatusMessage, nodeId);
+ LOG.debug("Early port status message body is {}", portStatusMessage);
portStatusMessages.add(portStatusMessage);
}
return result;
}
+ @Override
+ public String toString() {
+ return getLOGValue();
+ }
+
public void setOutboundQueueProvider(final OutboundQueue outboundQueueProvider) {
this.outboundQueueProvider = outboundQueueProvider;
}
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.base.Verify;
+import com.google.common.collect.Iterators;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.JdkFutureAdapters;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;
-import java.math.BigInteger;
import java.util.Collection;
-import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.opendaylight.openflowplugin.api.openflow.lifecycle.ContextChainMastershipState;
import org.opendaylight.openflowplugin.api.openflow.lifecycle.ContextChainState;
import org.opendaylight.openflowplugin.api.openflow.lifecycle.MastershipChangeListener;
-import org.opendaylight.openflowplugin.api.openflow.md.core.SwitchConnectionDistinguisher;
import org.opendaylight.openflowplugin.api.openflow.md.core.TranslatorKey;
import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
import org.opendaylight.openflowplugin.api.openflow.registry.ItemLifeCycleRegistry;
import org.opendaylight.openflowplugin.impl.registry.group.DeviceGroupRegistryImpl;
import org.opendaylight.openflowplugin.impl.registry.meter.DeviceMeterRegistryImpl;
import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
+import org.opendaylight.openflowplugin.impl.services.util.RequestContextUtil;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor;
-import org.opendaylight.openflowplugin.openflow.md.core.session.SwitchConnectionCookieOFImpl;
import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.experimenter.message.service.rev151020.ExperimenterMessageFromDevBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
private volatile ConnectionContext primaryConnectionContext;
private final DeviceState deviceState;
private final DataBroker dataBroker;
- private final Map<SwitchConnectionDistinguisher, ConnectionContext> auxiliaryConnectionContexts;
+ private final Collection<RequestContext<?>> requestContexts = new HashSet<>();
private TransactionChainManager transactionChainManager;
private DeviceFlowRegistry deviceFlowRegistry;
private DeviceGroupRegistry deviceGroupRegistry;
this.myManager = contextManager;
this.deviceState = new DeviceStateImpl();
this.dataBroker = dataBroker;
- this.auxiliaryConnectionContexts = new HashMap<>();
this.messageSpy = messageSpy;
this.packetInLimiter = new PacketInRateLimiter(primaryConnectionContext.getConnectionAdapter(),
transactionChainManager.initialSubmitWriteTransaction()));
}
- @Override
- public void addAuxiliaryConnectionContext(final ConnectionContext connectionContext) {
- final SwitchConnectionDistinguisher connectionDistinguisher = createConnectionDistinguisher(connectionContext);
- auxiliaryConnectionContexts.put(connectionDistinguisher, connectionContext);
- }
-
- private static SwitchConnectionDistinguisher createConnectionDistinguisher(final ConnectionContext connectionContext) {
- return new SwitchConnectionCookieOFImpl(connectionContext.getFeatures().getAuxiliaryId());
- }
-
- @Override
- public void removeAuxiliaryConnectionContext(final ConnectionContext connectionContext) {
- final SwitchConnectionDistinguisher connectionDistinguisher = createConnectionDistinguisher(connectionContext);
- LOG.debug("auxiliary connection dropped: {}, nodeId:{}", connectionContext.getConnectionAdapter()
- .getRemoteAddress(), getDeviceInfo().getLOGValue());
- auxiliaryConnectionContexts.remove(connectionDistinguisher);
- }
-
@Override
public DeviceState getDeviceState() {
return deviceState;
return primaryConnectionContext;
}
- @Override
- public ConnectionContext getAuxiliaryConnectionContexts(final BigInteger cookie) {
- return auxiliaryConnectionContexts.get(new SwitchConnectionCookieOFImpl(cookie.longValue()));
- }
-
@Override
public DeviceFlowRegistry getDeviceFlowRegistry() {
return deviceFlowRegistry;
@Override
public void onPublished() {
- Verify.verify(ContextState.INITIALIZATION.equals(getState()));
+ Verify.verify(ContextState.INITIALIZATION.equals(state));
this.state = ContextState.WORKING;
primaryConnectionContext.getConnectionAdapter().setPacketInFiltering(false);
}
return extensionConverterProvider;
}
- @Override
- public synchronized void shutdownConnection() {
- if (LOG.isDebugEnabled()) {
- LOG.debug("Shutdown method for node {}", getDeviceInfo().getLOGValue());
- }
- if (ContextState.TERMINATION.equals(getState())) {
- LOG.debug("DeviceCtx for Node {} is in termination process.", getDeviceInfo().getLOGValue());
- return;
- }
-
- if (ConnectionContext.CONNECTION_STATE.RIP.equals(getPrimaryConnectionContext().getConnectionState())) {
- LOG.debug("ConnectionCtx for Node {} is in RIP state.", getDeviceInfo().getLOGValue());
- return;
- }
-
- // Terminate Auxiliary Connection
- for (final ConnectionContext connectionContext : auxiliaryConnectionContexts.values()) {
- LOG.debug("Closing auxiliary connection {}", connectionContext.getNodeId());
- connectionContext.closeConnection(false);
- }
-
- // Terminate Primary Connection
- getPrimaryConnectionContext().closeConnection(true);
-
- // Close all datastore registries
- if (initialized) {
- deviceGroupRegistry.close();
- deviceFlowRegistry.close();
- deviceMeterRegistry.close();
- }
- }
-
- @Override
- public ListenableFuture<Void> shuttingDownDataStoreTransactions() {
- return initialized
- ? this.transactionChainManager.shuttingDown()
- : Futures.immediateFuture(null);
- }
-
@VisibleForTesting
TransactionChainManager getTransactionChainManager() {
return this.transactionChainManager;
this.switchFeaturesMandatory = switchFeaturesMandatory;
}
- @Override
- public ContextState getState() {
- return this.state;
- }
-
@Override
public ListenableFuture<Void> stopClusterServices() {
return initialized
@Override
public void close() {
- //NOOP
+ if (ContextState.TERMINATION.equals(state)) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("DeviceContext for node {} is already in TERMINATION state.", getDeviceInfo().getLOGValue());
+ }
+
+ return;
+ }
+
+ state = ContextState.TERMINATION;
+
+ // Close all datastore registries and transactions
+ if (initialized) {
+ initialized = false;
+ deviceGroupRegistry.close();
+ deviceFlowRegistry.close();
+ deviceMeterRegistry.close();
+
+ Futures.addCallback(transactionChainManager.shuttingDown(), new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(@Nullable final Void result) {
+ transactionChainManager.close();
+ transactionChainManager = null;
+ }
+
+ @Override
+ public void onFailure(final Throwable t) {
+ transactionChainManager.close();
+ transactionChainManager = null;
+ }
+ });
+ }
+
+ for (final Iterator<RequestContext<?>> iterator = Iterators
+ .consumingIterator(requestContexts.iterator()); iterator.hasNext();) {
+ RequestContextUtil.closeRequestContextWithRpcError(iterator.next(), "Connection closed.");
+ }
}
@Override
return useSingleLayerSerialization && getDeviceInfo().getVersion() >= OFConstants.OFP_VERSION_1_3;
}
- @Override
- public boolean isSkipTableFeatures() {
- return this.skipTableFeatures;
- }
-
@Override
public void setSalRoleService(@Nonnull SalRoleService salRoleService) {
this.salRoleService = salRoleService;
@Override
public boolean onContextInstantiateService(final MastershipChangeListener mastershipChangeListener) {
-
LOG.info("Starting device context cluster services for node {}", deviceInfo.getLOGValue());
lazyTransactionManagerInitialization();
if (initializer.isPresent()) {
initializer
.get()
- .initialize(this, switchFeaturesMandatory, writerProvider, convertorExecutor)
+ .initialize(this, switchFeaturesMandatory, skipTableFeatures, writerProvider, convertorExecutor)
.get(DEVICE_INIT_TIMEOUT, TimeUnit.MILLISECONDS);
} else {
throw new ExecutionException(new ConnectionException("Unsupported version " + deviceInfo.getVersion()));
}
} catch (ExecutionException | InterruptedException | TimeoutException ex) {
- LOG.warn("Device {} cannot be initialized: ", deviceInfo.getLOGValue(), ex);
+ LOG.warn("Device {} cannot be initialized: {}", deviceInfo.getLOGValue(), ex.getMessage());
+ LOG.trace("Device {} cannot be initialized: ", deviceInfo.getLOGValue(), ex);
return false;
}
@Nullable
@Override
public <T> RequestContext<T> createRequestContext() {
- return new AbstractRequestContext<T>(deviceInfo.reserveXidForDeviceMessage()) {
+ final Long xid = deviceInfo.reserveXidForDeviceMessage();
+
+ final AbstractRequestContext<T> abstractRequestContext = new AbstractRequestContext<T>(xid) {
@Override
public void close() {
+ requestContexts.remove(this);
}
};
+ requestContexts.add(abstractRequestContext);
+ return abstractRequestContext;
}
private ListenableFuture<RpcResult<SetRoleOutput>> sendRoleChangeToDevice(final OfpRole newRole) {
*/
package org.opendaylight.openflowplugin.impl.device;
-import com.google.common.collect.Iterators;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import io.netty.util.HashedWheelTimer;
import io.netty.util.internal.ConcurrentSet;
import java.util.Collections;
-import java.util.Iterator;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueueHandlerRegistration;
+import org.opendaylight.openflowplugin.api.openflow.OFPContext;
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.impl.device.listener.OpenflowProtocolListenerFullImpl;
import org.opendaylight.openflowplugin.impl.services.sal.SalRoleServiceImpl;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemovedBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdatedBuilder;
private TranslatorLibrary translatorLibrary;
private final ConcurrentMap<DeviceInfo, DeviceContext> deviceContexts = new ConcurrentHashMap<>();
- private final Set<DeviceInfo> notificationCreateNodeSend = new ConcurrentSet<>();
+ private final Set<KeyedInstanceIdentifier<Node, NodeKey>> notificationCreateNodeSend = new ConcurrentSet<>();
private long barrierIntervalNanos;
private int barrierCountLimit;
@Override
public void close() {
- for (final Iterator<DeviceContext> iterator = Iterators.consumingIterator(deviceContexts.values().iterator());
- iterator.hasNext();) {
- final DeviceContext deviceCtx = iterator.next();
- deviceCtx.shutdownConnection();
- deviceCtx.shuttingDownDataStoreTransactions();
- }
-
+ deviceContexts.values().forEach(OFPContext::close);
+ deviceContexts.clear();
Optional.ofNullable(spyPool).ifPresent(ScheduledThreadPoolExecutor::shutdownNow);
spyPool = null;
}
@Override
- public CheckedFuture<Void, TransactionCommitFailedException> removeDeviceFromOperationalDS(final KeyedInstanceIdentifier<Node, NodeKey> ii) {
+ public CheckedFuture<Void, TransactionCommitFailedException> removeDeviceFromOperationalDS(@Nonnull final KeyedInstanceIdentifier<Node, NodeKey> ii) {
final WriteTransaction delWtx = dataBroker.newWriteOnlyTransaction();
delWtx.delete(LogicalDatastoreType.OPERATIONAL, ii);
final CheckedFuture<Void, TransactionCommitFailedException> delFuture = delWtx.submit();
return delFuture;
}
- @Override
- public CheckedFuture<Void, TransactionCommitFailedException> removeDeviceFromOperationalDS(final DeviceInfo deviceInfo) {
- return this.removeDeviceFromOperationalDS(deviceInfo.getNodeInstanceIdentifier());
- }
-
public DeviceContext createContext(@Nonnull final ConnectionContext connectionContext) {
LOG.info("ConnectionEvent: Device connected to controller, Device:{}, NodeId:{}",
}
}
- private void sendNodeRemovedNotification(final DeviceInfo deviceInfo) {
- notificationCreateNodeSend.remove(deviceInfo);
- NodeRemovedBuilder builder = new NodeRemovedBuilder();
- builder.setNodeRef(new NodeRef(deviceInfo.getNodeInstanceIdentifier()));
- if (LOG.isDebugEnabled()) {
- LOG.debug("Publishing node removed notification for {}", deviceInfo.getLOGValue());
- }
- notificationPublishService.offerNotification(builder.build());
- }
-
-
@Override
public void onDeviceRemoved(final DeviceInfo deviceInfo) {
- this.sendNodeRemovedNotification(deviceInfo);
deviceContexts.remove(deviceInfo);
if (LOG.isDebugEnabled()) {
LOG.debug("Device context removed for node {}", deviceInfo.getLOGValue());
}
@Override
- public long getBarrierIntervalNanos() {
- return barrierIntervalNanos;
- }
-
- @Override
- public int getBarrierCountLimit() {
- return barrierCountLimit;
+ public void sendNodeRemovedNotification(@Nonnull final KeyedInstanceIdentifier<Node, NodeKey> instanceIdentifier) {
+ if (notificationCreateNodeSend.remove(instanceIdentifier)) {
+ NodeRemovedBuilder builder = new NodeRemovedBuilder();
+ builder.setNodeRef(new NodeRef(instanceIdentifier));
+ LOG.info("Publishing node removed notification for {}", instanceIdentifier.firstKeyOf(Node.class).getId());
+ notificationPublishService.offerNotification(builder.build());
+ }
}
@Override
- public void sendNodeAddedNotification(@Nonnull final DeviceInfo deviceInfo) {
- if (!notificationCreateNodeSend.contains(deviceInfo)) {
- notificationCreateNodeSend.add(deviceInfo);
+ public void sendNodeAddedNotification(@Nonnull final KeyedInstanceIdentifier<Node, NodeKey> instanceIdentifier) {
+ if (!notificationCreateNodeSend.contains(instanceIdentifier)) {
+ notificationCreateNodeSend.add(instanceIdentifier);
+ final NodeId id = instanceIdentifier.firstKeyOf(Node.class).getId();
NodeUpdatedBuilder builder = new NodeUpdatedBuilder();
- builder.setId(deviceInfo.getNodeId());
- builder.setNodeRef(new NodeRef(deviceInfo.getNodeInstanceIdentifier()));
- if (LOG.isDebugEnabled()) {
- LOG.debug("Publishing node added notification for {}", deviceInfo.getLOGValue());
- }
+ builder.setId(id);
+ builder.setNodeRef(new NodeRef(instanceIdentifier));
+ LOG.info("Publishing node added notification for {}", id);
notificationPublishService.offerNotification(builder.build());
}
}
@GuardedBy("txLock")
private ListenableFuture<Void> txChainShuttingDown() {
+ boolean wasSubmitEnabled = submitIsEnabled;
submitIsEnabled = false;
ListenableFuture<Void> future;
- if (txChainFactory == null) {
+
+ if (!wasSubmitEnabled || txChainFactory == null) {
// stay with actual thread
future = Futures.immediateCheckedFuture(null);
+
+ if (wTx != null) {
+ wTx.cancel();
+ wTx = null;
+ }
} else if (wTx == null) {
// hijack md-sal thread
future = lastSubmittedFuture;
future = wTx.submit();
wTx = null;
}
+
return future;
}
/**
* Perform initial information gathering and store them to operational datastore
* @param deviceContext device context
+ * @param switchFeaturesMandatory is switch features mandatory
+ * @param skipTableFeatures skip collecting of table features
* @param multipartWriterProvider multipart writer provider
+ * @param convertorExecutor convertor executor
*/
public Future<Void> initialize(@Nonnull final DeviceContext deviceContext,
final boolean switchFeaturesMandatory,
+ final boolean skipTableFeatures,
@Nullable final MultipartWriterProvider multipartWriterProvider,
@Nullable final ConvertorExecutor convertorExecutor) throws ExecutionException,InterruptedException {
Preconditions.checkNotNull(deviceContext);
}
// Get information about device
- return initializeNodeInformation(deviceContext, switchFeaturesMandatory, multipartWriterProvider, convertorExecutor);
+ return initializeNodeInformation(deviceContext, switchFeaturesMandatory, skipTableFeatures,
+ multipartWriterProvider, convertorExecutor);
}
protected abstract Future<Void> initializeNodeInformation(@Nonnull final DeviceContext deviceContext,
final boolean switchFeaturesMandatory,
+ final boolean skipTableFeatures,
@Nullable final MultipartWriterProvider multipartWriterProvider,
@Nullable final ConvertorExecutor convertorExecutor);
}
* @param version the initializer version
* @param initializer the initializer instance
*/
- public void register(final Short version, final AbstractDeviceInitializer initializer) {
+ void register(final Short version, final AbstractDeviceInitializer initializer) {
initializers.put(version, initializer);
}
@Override
protected Future<Void> initializeNodeInformation(@Nonnull final DeviceContext deviceContext,
final boolean switchFeaturesMandatory,
+ final boolean skipTableFeatures,
@Nullable final MultipartWriterProvider multipartWriterProvider,
@Nullable final ConvertorExecutor convertorExecutor) {
final ConnectionContext connectionContext = Preconditions.checkNotNull(deviceContext.getPrimaryConnectionContext());
new SingleLayerMultipartCollectorService(deviceContext, deviceContext);
return Futures.transform(service.handleServiceCall(multipartType), new Function<RpcResult<List<MultipartReply>>, Boolean>() {
- @Nullable
+ @Nonnull
@Override
public Boolean apply(final RpcResult<List<MultipartReply>> input) {
return input.isSuccessful();
new MultiLayerMultipartCollectorService(deviceContext, deviceContext);
return Futures.transform(service.handleServiceCall(multipartType), new Function<RpcResult<List<org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply>>, Boolean>() {
- @Nullable
+ @Nonnull
@Override
public Boolean apply(final RpcResult<List<org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply>> input) {
return input.isSuccessful();
@Override
protected Future<Void> initializeNodeInformation(@Nonnull final DeviceContext deviceContext,
final boolean switchFeaturesMandatory,
+ final boolean skipTableFeatures,
@Nullable final MultipartWriterProvider multipartWriterProvider,
@Nullable final ConvertorExecutor convertorExecutor) {
final ConnectionContext connectionContext = Preconditions.checkNotNull(deviceContext.getPrimaryConnectionContext());
convertorExecutor);
final List<ListenableFuture<RpcResult<List<OfHeader>>>> futures = new ArrayList<>();
- futures.add(requestAndProcessMultipart(MultipartType.OFPMPMETERFEATURES, deviceContext, multipartWriterProvider, convertorExecutor));
- futures.add(requestAndProcessMultipart(MultipartType.OFPMPGROUPFEATURES, deviceContext, multipartWriterProvider, convertorExecutor));
- futures.add(requestAndProcessMultipart(MultipartType.OFPMPTABLEFEATURES, deviceContext, multipartWriterProvider, convertorExecutor));
- futures.add(requestAndProcessMultipart(MultipartType.OFPMPPORTDESC, deviceContext, multipartWriterProvider, convertorExecutor));
+ futures.add(requestAndProcessMultipart(MultipartType.OFPMPMETERFEATURES, deviceContext, skipTableFeatures, multipartWriterProvider, convertorExecutor));
+ futures.add(requestAndProcessMultipart(MultipartType.OFPMPGROUPFEATURES, deviceContext, skipTableFeatures, multipartWriterProvider, convertorExecutor));
+ futures.add(requestAndProcessMultipart(MultipartType.OFPMPTABLEFEATURES, deviceContext, skipTableFeatures, multipartWriterProvider, convertorExecutor));
+ futures.add(requestAndProcessMultipart(MultipartType.OFPMPPORTDESC, deviceContext, skipTableFeatures, multipartWriterProvider, convertorExecutor));
return Futures.transform(
(switchFeaturesMandatory ? Futures.allAsList(futures) : Futures.successfulAsList(futures)),
* Request multipart of specified type and then run some processing on it
* @param type multipart type
* @param deviceContext device context
+ * @param skipTableFeatures skip collecting of table features
* @param multipartWriterProvider multipart writer provider
* @param convertorExecutor convertor executor
* @return list of multipart messages unified to parent interface
*/
private static ListenableFuture<RpcResult<List<OfHeader>>> requestAndProcessMultipart(final MultipartType type,
final DeviceContext deviceContext,
+ final boolean skipTableFeatures,
final MultipartWriterProvider multipartWriterProvider,
@Nullable final ConvertorExecutor convertorExecutor) {
final ListenableFuture<RpcResult<List<OfHeader>>> rpcResultListenableFuture =
- MultipartType.OFPMPTABLEFEATURES.equals(type) && deviceContext.isSkipTableFeatures()
+ MultipartType.OFPMPTABLEFEATURES.equals(type) && skipTableFeatures
? RpcResultBuilder.<List<OfHeader>>success().buildFuture()
: requestMultipart(type, deviceContext);
new SingleLayerMultipartCollectorService(deviceContext, deviceContext);
return Futures.transform(service.handleServiceCall(multipartType), new Function<RpcResult<List<MultipartReply>>, RpcResult<List<OfHeader>>>() {
- @Nullable
+ @Nonnull
@Override
public RpcResult<List<OfHeader>> apply(final RpcResult<List<MultipartReply>> input) {
if (Objects.isNull(input.getResult()) && input.isSuccessful()) {
return input.isSuccessful()
? RpcResultBuilder.success(input
- .getResult()
+ .getResult()
.stream()
- .map(reply -> (OfHeader) reply)
+ .map(OfHeader.class::cast)
.collect(Collectors.toList()))
.build()
: RpcResultBuilder.<List<OfHeader>>failed()
new MultiLayerMultipartCollectorService(deviceContext, deviceContext);
return Futures.transform(service.handleServiceCall(multipartType), new Function<RpcResult<List<org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply>>, RpcResult<List<OfHeader>>>() {
- @Nullable
+ @Nonnull
@Override
public RpcResult<List<OfHeader>> apply(final RpcResult<List<org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply>> input) {
if (Objects.isNull(input.getResult()) && input.isSuccessful()) {
? RpcResultBuilder.success(input
.getResult()
.stream()
- .map(reply -> (OfHeader) reply)
+ .map(OfHeader.class::cast)
.collect(Collectors.toList()))
.build()
: RpcResultBuilder.<List<OfHeader>>failed()
package org.opendaylight.openflowplugin.impl.lifecycle;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
import com.google.common.base.Verify;
+import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import io.netty.util.HashedWheelTimer;
-import io.netty.util.Timeout;
-import io.netty.util.TimerTask;
-import io.netty.util.internal.ConcurrentSet;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.Optional;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.annotation.Nonnull;
import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsContext;
import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsManager;
import org.opendaylight.openflowplugin.impl.util.DeviceStateUtil;
+import org.opendaylight.openflowplugin.impl.util.ItemScheduler;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ContextChainHolderImpl implements ContextChainHolder {
-
private static final Logger LOG = LoggerFactory.getLogger(ContextChainHolderImpl.class);
private static final String CONTEXT_CREATED_FOR_CONNECTION = " context created for connection: {}";
- private static final long DEFAULT_CHECK_ROLE_MASTER = 10000L;
- private static final String SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.ServiceEntityType";
+ private static final long CHECK_ROLE_MASTER_TIMEOUT = 20000L;
+ private static final long CHECK_ROLE_MASTER_TOLERANCE = CHECK_ROLE_MASTER_TIMEOUT / 2;
+ private static final long REMOVE_DEVICE_FROM_DS_TIMEOUT = 5000L;
private static final String ASYNC_SERVICE_ENTITY_TYPE = "org.opendaylight.mdsal.AsyncServiceCloseEntityType";
- private final ConcurrentHashMap<DeviceInfo, ContextChain> contextChainMap = new ConcurrentHashMap<>();
- private final ConcurrentHashMap<DeviceInfo, ContextChain> withoutRoleChains = new ConcurrentHashMap<>();
- private final List<DeviceInfo> markToBeRemoved = new ArrayList<>();
- private final HashedWheelTimer timer;
- private final Long checkRoleMaster;
-
+ private final Map<DeviceInfo, ContextChain> contextChainMap = Collections.synchronizedMap(new HashMap<>());
private DeviceManager deviceManager;
private RpcManager rpcManager;
private StatisticsManager statisticsManager;
private EntityOwnershipListenerRegistration eosListenerRegistration;
private ClusterSingletonServiceProvider singletonServicesProvider;
- private boolean timerIsRunningRole;
+ private final ItemScheduler<DeviceInfo, ContextChain> scheduler;
+ private final ExecutorService executorService;
+
+ public ContextChainHolderImpl(final HashedWheelTimer timer, final ExecutorService executorService) {
+ this.scheduler = new ItemScheduler<>(
+ timer,
+ CHECK_ROLE_MASTER_TIMEOUT,
+ CHECK_ROLE_MASTER_TOLERANCE,
+ ContextChain::makeDeviceSlave);
- public ContextChainHolderImpl(final HashedWheelTimer timer) {
- this.timerIsRunningRole = false;
- this.timer = timer;
- this.checkRoleMaster = DEFAULT_CHECK_ROLE_MASTER;
+ this.executorService = executorService;
}
@Override
@Override
public ContextChain createContextChain(final ConnectionContext connectionContext) {
-
final DeviceInfo deviceInfo = connectionContext.getDeviceInfo();
final String deviceInfoLOGValue = deviceInfo.getLOGValue();
+ final ContextChain contextChain = new ContextChainImpl(connectionContext);
if (LOG.isDebugEnabled()) {
- LOG.debug("Creating a new chain" + CONTEXT_CREATED_FOR_CONNECTION, deviceInfoLOGValue);
+ LOG.debug("Context chain" + CONTEXT_CREATED_FOR_CONNECTION, deviceInfoLOGValue);
}
- final ContextChain contextChain = new ContextChainImpl(connectionContext);
- final LifecycleService lifecycleService = new LifecycleServiceImpl(this);
+ final LifecycleService lifecycleService = new LifecycleServiceImpl(this, executorService);
lifecycleService.registerDeviceRemovedHandler(deviceManager);
lifecycleService.registerDeviceRemovedHandler(rpcManager);
lifecycleService.registerDeviceRemovedHandler(statisticsManager);
LOG.debug("RPC" + CONTEXT_CREATED_FOR_CONNECTION, deviceInfoLOGValue);
}
- final StatisticsContext statisticsContext
- = statisticsManager.createContext(deviceContext);
+ final StatisticsContext statisticsContext = statisticsManager.createContext(deviceContext);
if (LOG.isDebugEnabled()) {
LOG.debug("Statistics" + CONTEXT_CREATED_FOR_CONNECTION, deviceInfoLOGValue);
contextChain.addContext(deviceContext);
contextChain.addContext(rpcContext);
contextChain.addContext(statisticsContext);
- this.withoutRoleChains.put(deviceInfo, contextChain);
- if (!this.timerIsRunningRole) {
- this.startTimerRole();
- }
+
+ LOG.info("Starting timer for setting SLAVE role on node {} if no role will be set in {}s.",
+ deviceInfo.getLOGValue(), CHECK_ROLE_MASTER_TIMEOUT / 1000L);
+ scheduler.add(deviceInfo, contextChain);
+ scheduler.startIfNotRunning();
deviceContext.onPublished();
contextChain.registerServices(this.singletonServicesProvider);
-
return contextChain;
}
@Override
- public ListenableFuture<Void> destroyContextChain(final DeviceInfo deviceInfo) {
- ContextChain chain = contextChainMap.remove(deviceInfo);
- if (chain != null) {
- chain.close();
- }
- if (markToBeRemoved.contains(deviceInfo)) {
- markToBeRemoved.remove(deviceInfo);
- LOG.info("Removing device: {} from DS", deviceInfo.getLOGValue());
- return deviceManager.removeDeviceFromOperationalDS(deviceInfo);
- } else {
- return Futures.immediateFuture(null);
- }
+ public synchronized void destroyContextChain(final DeviceInfo deviceInfo) {
+ Optional.ofNullable(contextChainMap.remove(deviceInfo)).ifPresent(contextChain -> {
+ deviceManager.sendNodeRemovedNotification(deviceInfo.getNodeInstanceIdentifier());
+ contextChain.close();
+ });
}
@Override
public ConnectionStatus deviceConnected(final ConnectionContext connectionContext) throws Exception {
-
- DeviceInfo deviceInfo = connectionContext.getDeviceInfo();
+ final DeviceInfo deviceInfo = connectionContext.getDeviceInfo();
+ final ContextChain contextChain = contextChainMap.get(deviceInfo);
LOG.info("Device {} connected.", deviceInfo.getLOGValue());
- ContextChain contextChain = contextChainMap.get(deviceInfo);
+
if (contextChain != null) {
if (contextChain.addAuxiliaryConnection(connectionContext)) {
LOG.info("An auxiliary connection was added to device: {}", deviceInfo.getLOGValue());
@Override
public void onNotAbleToStartMastership(final DeviceInfo deviceInfo, @Nonnull final String reason, final boolean mandatory) {
- this.withoutRoleChains.remove(deviceInfo);
LOG.warn("Not able to set MASTER role on device {}, reason: {}", deviceInfo.getLOGValue(), reason);
- if (mandatory && contextChainMap.containsKey(deviceInfo)) {
- LOG.warn("This mastering is mandatory, destroying context chain and closing connection.");
- Futures.transform(contextChainMap.get(deviceInfo).stopChain(), new Function<Void, Object>() {
- @Nullable
- @Override
- public Object apply(@Nullable Void aVoid) {
- destroyContextChain(deviceInfo);
- return null;
- }
- });
+
+ if (!mandatory) {
+ return;
}
+
+ Optional.ofNullable(contextChainMap.get(deviceInfo)).ifPresent(contextChain -> {
+ LOG.warn("This mastering is mandatory, destroying context chain and closing connection for device {}.", deviceInfo.getLOGValue());
+ addDestroyChainCallback(contextChain.stopChain(), deviceInfo);
+ });
}
@Override
- public void onMasterRoleAcquired(final DeviceInfo deviceInfo,
- @Nonnull final ContextChainMastershipState mastershipState) {
- this.withoutRoleChains.remove(deviceInfo);
- ContextChain contextChain = contextChainMap.get(deviceInfo);
- if (contextChain != null) {
+ public void onMasterRoleAcquired(final DeviceInfo deviceInfo, @Nonnull final ContextChainMastershipState mastershipState) {
+ scheduler.remove(deviceInfo);
+
+ Optional.ofNullable(contextChainMap.get(deviceInfo)).ifPresent(contextChain -> {
if (contextChain.isMastered(mastershipState)) {
LOG.info("Role MASTER was granted to device {}", deviceInfo.getLOGValue());
- this.sendNotificationNodeAdded(deviceInfo);
+ deviceManager.sendNodeAddedNotification(deviceInfo.getNodeInstanceIdentifier());
}
- }
+ });
}
@Override
public void onSlaveRoleAcquired(final DeviceInfo deviceInfo) {
- this.withoutRoleChains.remove(deviceInfo);
- ContextChain contextChain = contextChainMap.get(deviceInfo);
- if (contextChain != null) {
- contextChain.makeContextChainStateSlave();
- }
+ Optional.ofNullable(contextChainMap.get(deviceInfo)).ifPresent(ContextChain::makeContextChainStateSlave);
}
@Override
public void onSlaveRoleNotAcquired(final DeviceInfo deviceInfo) {
- this.withoutRoleChains.remove(deviceInfo);
- ContextChain contextChain = contextChainMap.get(deviceInfo);
- if (contextChain != null) {
- destroyContextChain(deviceInfo);
- }
+ Optional.ofNullable(contextChainMap.get(deviceInfo)).ifPresent(contextChain -> destroyContextChain(deviceInfo));
}
@Override
public void onDeviceDisconnected(final ConnectionContext connectionContext) {
-
final DeviceInfo deviceInfo = connectionContext.getDeviceInfo();
- if (deviceInfo != null) {
- ContextChain chain = contextChainMap.get(deviceInfo);
- if (chain != null) {
- if (chain.auxiliaryConnectionDropped(connectionContext)) {
- LOG.info("Auxiliary connection from device {} disconnected.", deviceInfo.getLOGValue());
- } else {
- LOG.info("Device {} disconnected.", deviceInfo.getLOGValue());
- Futures.transform(chain.connectionDropped(), new Function<Void, Object>() {
- @Nullable
- @Override
- public Object apply(@Nullable Void aVoid) {
- destroyContextChain(deviceInfo);
- return null;
- }
- });
- }
- }
+
+ if (Objects.isNull(deviceInfo)) {
+ return;
}
+
+ Optional.ofNullable(contextChainMap.get(deviceInfo)).ifPresent(contextChain -> {
+ if (contextChain.auxiliaryConnectionDropped(connectionContext)) {
+ LOG.info("Auxiliary connection from device {} disconnected.", deviceInfo.getLOGValue());
+ } else {
+ LOG.info("Device {} disconnected.", deviceInfo.getLOGValue());
+ addDestroyChainCallback(contextChain.connectionDropped(), deviceInfo);
+ }
+ });
}
@Override
- public void changeEntityOwnershipService(final EntityOwnershipService entityOwnershipService) {
+ public void changeEntityOwnershipService(@Nonnull final EntityOwnershipService entityOwnershipService) {
if (Objects.nonNull(this.eosListenerRegistration)) {
- LOG.warn("EOS Listener already registered.");
+ LOG.warn("Entity ownership service listener is already registered.");
} else {
this.eosListenerRegistration = Verify.verifyNotNull(entityOwnershipService.registerListener
(ASYNC_SERVICE_ENTITY_TYPE, this));
}
}
- private void startTimerRole() {
- this.timerIsRunningRole = true;
- if (LOG.isDebugEnabled()) {
- LOG.debug("There is a context chain without role, starting timer.");
- }
- timer.newTimeout(new RoleTimerTask(), this.checkRoleMaster, TimeUnit.MILLISECONDS);
- }
-
- private void stopTimerRole() {
- this.timerIsRunningRole = false;
- if (LOG.isDebugEnabled()) {
- LOG.debug("There are no context chains, stopping timer.");
- }
- }
-
- private void timerTickRole() {
- if (!withoutRoleChains.isEmpty()) {
- this.withoutRoleChains.forEach((deviceInfo, contextChain) -> contextChain.makeDeviceSlave());
- timer.newTimeout(new RoleTimerTask(), this.checkRoleMaster, TimeUnit.MILLISECONDS);
- } else {
- this.stopTimerRole();
- }
- }
-
@VisibleForTesting
boolean checkAllManagers() {
return Objects.nonNull(deviceManager) && Objects.nonNull(rpcManager) && Objects.nonNull(statisticsManager);
@Override
public void close() throws Exception {
- this.contextChainMap.forEach((deviceInfo, contextChain) -> {
+ scheduler.close();
+
+ contextChainMap.forEach((deviceInfo, contextChain) -> {
if (contextChain.isMastered(ContextChainMastershipState.CHECK)) {
- contextChain.stopChain();
+ addDestroyChainCallback(contextChain.stopChain(), deviceInfo);
+ } else {
+ destroyContextChain(deviceInfo);
}
- contextChain.close();
});
+
+ contextChainMap.clear();
+
+
if (Objects.nonNull(eosListenerRegistration)) {
eosListenerRegistration.close();
+ eosListenerRegistration = null;
}
}
@Override
public void ownershipChanged(EntityOwnershipChange entityOwnershipChange) {
- if (!entityOwnershipChange.hasOwner()) {
- final YangInstanceIdentifier yii = entityOwnershipChange.getEntity().getId();
- final YangInstanceIdentifier.NodeIdentifierWithPredicates niiwp =
- (YangInstanceIdentifier.NodeIdentifierWithPredicates) yii.getLastPathArgument();
- String entityName = niiwp.getKeyValues().values().iterator().next().toString();
+ if (entityOwnershipChange.hasOwner()) {
+ return;
+ }
+
+ final String entityName = getEntityNameFromOwnershipChange(entityOwnershipChange);
+
+ if (Objects.nonNull(entityName)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Entity {} has no owner", entityName);
}
- if (entityName != null ){
- final NodeId nodeId = new NodeId(entityName);
- DeviceInfo inMap = null;
- for (Map.Entry<DeviceInfo, ContextChain> entry : contextChainMap.entrySet()) {
- if (entry.getKey().getNodeId().equals(nodeId)) {
- inMap = entry.getKey();
- break;
- }
- }
- if (Objects.nonNull(inMap)) {
- markToBeRemoved.add(inMap);
- } else {
- try {
- LOG.info("Removing device: {} from DS", nodeId);
- deviceManager
- .removeDeviceFromOperationalDS(DeviceStateUtil.createNodeInstanceIdentifier(nodeId))
- .checkedGet(5L, TimeUnit.SECONDS);
- } catch (TimeoutException | TransactionCommitFailedException e) {
- LOG.info("Not able to remove device {} from DS. Probably removed by another cluster node.",
- nodeId);
- }
- }
+ final NodeId nodeId = new NodeId(entityName);
+
+ try {
+ final KeyedInstanceIdentifier<Node, NodeKey> nodeInstanceIdentifier =
+ DeviceStateUtil.createNodeInstanceIdentifier(nodeId);
+
+ deviceManager.sendNodeRemovedNotification(nodeInstanceIdentifier);
+
+ LOG.info("Removing device {} from operational DS", nodeId);
+ deviceManager
+ .removeDeviceFromOperationalDS(nodeInstanceIdentifier)
+ .checkedGet(REMOVE_DEVICE_FROM_DS_TIMEOUT, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException | TransactionCommitFailedException e) {
+ LOG.info("Not able to remove device {} from operational DS. Probably removed by another cluster node.",
+ nodeId);
}
}
}
- private void sendNotificationNodeAdded(final DeviceInfo deviceInfo) {
- this.deviceManager.sendNodeAddedNotification(deviceInfo);
+ private String getEntityNameFromOwnershipChange(final EntityOwnershipChange entityOwnershipChange) {
+ final YangInstanceIdentifier.NodeIdentifierWithPredicates lastIdArgument =
+ (YangInstanceIdentifier.NodeIdentifierWithPredicates) entityOwnershipChange
+ .getEntity()
+ .getId()
+ .getLastPathArgument();
+
+ return lastIdArgument
+ .getKeyValues()
+ .values()
+ .iterator()
+ .next()
+ .toString();
}
- private class RoleTimerTask implements TimerTask {
+ private void addDestroyChainCallback(final ListenableFuture<Void> future, final DeviceInfo deviceInfo) {
+ scheduler.remove(deviceInfo);
- @Override
- public void run(Timeout timeout) throws Exception {
- timerTickRole();
- }
+ Futures.addCallback(future, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(@Nullable final Void aVoid) {
+ destroyContextChain(deviceInfo);
+ }
+ @Override
+ public void onFailure(@Nonnull final Throwable throwable) {
+ destroyContextChain(deviceInfo);
+ }
+ });
}
-}
-
+}
\ No newline at end of file
private ConnectionContext primaryConnection;
private Set<ConnectionContext> auxiliaryConnections = new ConcurrentSet<>();
- private volatile ContextChainState contextChainState;
+ private volatile ContextChainState contextChainState = ContextChainState.UNDEFINED;
- private AtomicBoolean masterStateOnDevice;
- private AtomicBoolean initialGathering;
- private AtomicBoolean initialSubmitting;
- private AtomicBoolean registryFilling;
+ private final AtomicBoolean masterStateOnDevice = new AtomicBoolean(false);
+ private final AtomicBoolean initialGathering = new AtomicBoolean(false);
+ private final AtomicBoolean initialSubmitting = new AtomicBoolean(false);
+ private final AtomicBoolean registryFilling = new AtomicBoolean(false);
+ private final AtomicBoolean rpcRegistration = new AtomicBoolean(false);
ContextChainImpl(final ConnectionContext connectionContext) {
this.primaryConnection = connectionContext;
- this.contextChainState = ContextChainState.UNDEFINED;
- this.masterStateOnDevice = new AtomicBoolean(false);
- this.initialGathering = new AtomicBoolean(false);
- this.initialSubmitting = new AtomicBoolean(false);
- this.registryFilling = new AtomicBoolean(false);
this.deviceInfo = connectionContext.getDeviceInfo();
}
@Override
public ListenableFuture<Void> stopChain() {
- //TODO: stopClusterServices change parameter
final List<ListenableFuture<Void>> futureList = new ArrayList<>();
futureList.add(statisticsContext.stopClusterServices());
futureList.add(rpcContext.stopClusterServices());
this.initialSubmitting.set(false);
this.initialGathering.set(false);
this.masterStateOnDevice.set(false);
+ this.rpcRegistration.set(false);
}
@Override
public void close() {
this.auxiliaryConnections.forEach(connectionContext -> connectionContext.closeConnection(false));
- if (this.primaryConnection.getConnectionState() != ConnectionContext.CONNECTION_STATE.RIP) {
- this.primaryConnection.closeConnection(true);
- }
+ this.primaryConnection.closeConnection(true);
lifecycleService.close();
deviceContext.close();
rpcContext.close();
statisticsContext.close();
+ unMasterMe();
}
@Override
LOG.debug("Device {}, initial gathering OK.", deviceInfo.getLOGValue());
this.initialGathering.set(true);
break;
+ case RPC_REGISTRATION:
+ LOG.debug("Device {}, RPC registration OK.", deviceInfo.getLOGValue());
+ this.rpcRegistration.set(true);
//Flow registry fill is not mandatory to work as a master
case INITIAL_FLOW_REGISTRY_FILL:
LOG.debug("Device {}, initial registry filling OK.", deviceInfo.getLOGValue());
case CHECK:
default:
}
+
final boolean result =
this.initialGathering.get() &&
this.masterStateOnDevice.get() &&
- this.initialSubmitting.get();
+ this.initialSubmitting.get() &&
+ this.rpcRegistration.get();
if (result && mastershipState != ContextChainMastershipState.CHECK) {
LOG.info("Device {} is able to work as master{}",
deviceInfo.getLOGValue(),
- this.registryFilling.get() ? " WITHOUT flow registry !!!" : ".");
+ this.registryFilling.get() ? "." : " WITHOUT flow registry !!!");
changeState(ContextChainState.WORKING_MASTER);
}
- return result;
- }
- @Override
- public boolean hasState() {
- return contextChainState == ContextChainState.WORKING_MASTER
- || contextChainState == ContextChainState.WORKING_SLAVE;
+ return result;
}
@Override
*/
package org.opendaylight.openflowplugin.impl.lifecycle;
+import com.google.common.base.MoreObjects;
import com.google.common.base.Verify;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.ExecutorService;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
+import org.opendaylight.openflowplugin.api.openflow.OFPContext.ContextState;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler;
private static final Logger LOG = LoggerFactory.getLogger(LifecycleServiceImpl.class);
+ private final List<DeviceRemovedHandler> deviceRemovedHandlers = new ArrayList<>();
+ private final MastershipChangeListener mastershipChangeListener;
+ private final ExecutorService executorService;
private ClusterSingletonServiceRegistration registration;
private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler;
- private final List<DeviceRemovedHandler> deviceRemovedHandlers = new ArrayList<>();
private ServiceGroupIdentifier serviceGroupIdentifier;
private DeviceInfo deviceInfo;
- private boolean terminationState = false;
- private final MastershipChangeListener mastershipChangeListener;
-
+ private volatile ContextState state = ContextState.INITIALIZATION;
- public LifecycleServiceImpl(@Nonnull final MastershipChangeListener mastershipChangeListener) {
+ public LifecycleServiceImpl(@Nonnull final MastershipChangeListener mastershipChangeListener,
+ @Nonnull final ExecutorService executorService) {
this.mastershipChangeListener = mastershipChangeListener;
+ this.executorService = executorService;
}
@Override
public void makeDeviceSlave(final DeviceContext deviceContext) {
-
- final DeviceInfo deviceInf = Objects.isNull(deviceInfo) ? deviceContext.getDeviceInfo() : deviceInfo;
+ deviceInfo = MoreObjects.firstNonNull(deviceInfo, deviceContext.getDeviceInfo());
Futures.addCallback(deviceContext.makeDeviceSlave(), new FutureCallback<RpcResult<SetRoleOutput>>() {
@Override
LOG.debug("Role SLAVE was successfully propagated on device, node {}",
deviceContext.getDeviceInfo().getLOGValue());
}
- mastershipChangeListener.onSlaveRoleAcquired(deviceInf);
+ mastershipChangeListener.onSlaveRoleAcquired(deviceInfo);
}
@Override
- public void onFailure(Throwable throwable) {
+ public void onFailure(@Nonnull Throwable throwable) {
LOG.warn("Was not able to set role SLAVE to device on node {} ",
deviceContext.getDeviceInfo().getLOGValue());
- mastershipChangeListener.onSlaveRoleNotAcquired(deviceInf);
+ mastershipChangeListener.onSlaveRoleNotAcquired(deviceInfo);
}
});
-
}
@Override
public void instantiateServiceInstance() {
+ executorService.submit(() -> {
+ LOG.info("Starting clustering services for node {}", deviceInfo.getLOGValue());
- LOG.info("Starting clustering MASTER services for node {}", deviceInfo.getLOGValue());
- if (!clusterInitializationPhaseHandler.onContextInstantiateService(mastershipChangeListener)) {
- mastershipChangeListener.onNotAbleToStartMastershipMandatory(deviceInfo, "Cannot initialize device.");
- }
+ if (!clusterInitializationPhaseHandler.onContextInstantiateService(mastershipChangeListener)) {
+ mastershipChangeListener.onNotAbleToStartMastershipMandatory(deviceInfo, "Cannot initialize device.");
+ }
+ });
}
@Override
public ListenableFuture<Void> closeServiceInstance() {
+ LOG.info("Closing clustering services for node {}", deviceInfo.getLOGValue());
return Futures.immediateFuture(null);
}
@Override
public void close() {
- if (terminationState) {
+ if (ContextState.TERMINATION.equals(state)) {
if (LOG.isDebugEnabled()) {
- LOG.debug("LifecycleService is already in TERMINATION state.");
+ LOG.debug("LifecycleService for node {} is already in TERMINATION state.", deviceInfo.getLOGValue());
}
} else {
- this.terminationState = true;
+ state = ContextState.TERMINATION;
// We are closing, so cleanup all managers now
deviceRemovedHandlers.forEach(h -> h.onDeviceRemoved(deviceInfo));
// If we are still registered and we are not already closing, then close the registration
if (Objects.nonNull(registration)) {
try {
- if (LOG.isDebugEnabled()) {
- LOG.debug("Closing clustering services for node {}", deviceInfo.getLOGValue());
- }
+ LOG.info("Closing clustering services registration for node {}", deviceInfo.getLOGValue());
registration.close();
+ registration = null;
} catch (final Exception e) {
- LOG.warn("Failed to close clustering services for node {} with exception: ",
+ LOG.warn("Failed to close clustering services registration for node {} with exception: ",
deviceInfo.getLOGValue(), e);
}
}
@Override
public void registerService(@Nonnull final ClusterSingletonServiceProvider singletonServiceProvider,
@Nonnull final DeviceContext deviceContext) {
-
+ Verify.verify(Objects.isNull(registration));
this.clusterInitializationPhaseHandler = deviceContext;
this.serviceGroupIdentifier = deviceContext.getServiceIdentifier();
this.deviceInfo = deviceContext.getDeviceInfo();
singletonServiceProvider.registerClusterSingletonService(this));
LOG.info("Registered clustering services for node {}", deviceInfo.getLOGValue());
-
}
@Override
@Override
public void store(final GroupId groupId) {
+ marks.remove(groupId);
groupIds.add(groupId);
}
@Override
public void store(final MeterId meterId) {
+ marks.remove(meterId);
meterIds.add(meterId);
}
import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
+import org.opendaylight.openflowplugin.api.openflow.lifecycle.ContextChainMastershipState;
import org.opendaylight.openflowplugin.api.openflow.lifecycle.MastershipChangeListener;
import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext;
import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageSpy;
*/
@Override
public void close() {
- //NOOP
+ if (ContextState.TERMINATION.equals(state)) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("RpcContext for node {} is already in TERMINATION state.", getDeviceInfo().getLOGValue());
+ }
+ } else {
+ this.state = ContextState.TERMINATION;
+ unregisterRPCs();
+ }
+ }
+
+ private void unregisterRPCs() {
+ for (final Iterator<Entry<Class<?>, RoutedRpcRegistration<?>>> iterator = Iterators
+ .consumingIterator(rpcRegistrations.entrySet().iterator()); iterator.hasNext(); ) {
+ final RoutedRpcRegistration<?> rpcRegistration = iterator.next().getValue();
+ rpcRegistration.unregisterPath(NodeContext.class, nodeInstanceIdentifier);
+ rpcRegistration.close();
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Closing RPC Registration of service {} for device {}.", rpcRegistration.getServiceType().getSimpleName(),
+ nodeInstanceIdentifier.getKey().getId().getValue());
+ }
+ }
}
@Override
return this.rpcRegistrations.isEmpty();
}
- @Override
- public ContextState getState() {
- return this.state;
- }
-
@Override
public ServiceGroupIdentifier getServiceIdentifier() {
return this.deviceInfo.getServiceIdentifier();
@Nullable
@Override
public Void apply(@Nullable Object input) {
- for (final Iterator<Entry<Class<?>, RoutedRpcRegistration<?>>> iterator = Iterators
- .consumingIterator(rpcRegistrations.entrySet().iterator()); iterator.hasNext(); ) {
- final RoutedRpcRegistration<?> rpcRegistration = iterator.next().getValue();
- rpcRegistration.unregisterPath(NodeContext.class, nodeInstanceIdentifier);
- rpcRegistration.close();
-
- if (LOG.isDebugEnabled()) {
- LOG.debug("Closing RPC Registration of service {} for device {}.", rpcRegistration.getServiceType().getSimpleName(),
- nodeInstanceIdentifier.getKey().getId().getValue());
- }
- }
-
+ unregisterRPCs();
return null;
}
});
@Override
public boolean onContextInstantiateService(final MastershipChangeListener mastershipChangeListener) {
-
+ LOG.info("Starting rpc context cluster services for node {}", deviceInfo.getLOGValue());
MdSalRegistrationUtils.registerServices(this, deviceContext, extensionConverterProvider, convertorExecutor);
if (isStatisticsRpcEnabled && !deviceContext.canUseSingleLayerSerialization()) {
convertorExecutor);
}
+ mastershipChangeListener.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.RPC_REGISTRATION);
return true;
}
}
}
public RpcContext createContext(final @Nonnull DeviceInfo deviceInfo, final @Nonnull DeviceContext deviceContext) {
- return new RpcContextImpl(
+ final RpcContextImpl rpcContext = new RpcContextImpl(
rpcProviderRegistry,
rpcRequestQuota,
deviceContext,
convertorExecutor,
notificationPublishService,
this.isStatisticsRpcEnabled);
+
+ contexts.put(deviceInfo, rpcContext);
+ return rpcContext;
}
@Override
@Override
public void close() {
- if (ContextState.TERMINATION.equals(getState())) {
+ if (ContextState.TERMINATION.equals(state)) {
if (LOG.isDebugEnabled()) {
LOG.debug("StatisticsContext for node {} is already in TERMINATION state.", getDeviceInfo().getLOGValue());
}
return itemLifeCycleListener;
}
- @Override
- public ContextState getState() {
- return this.state;
- }
-
@Override
public ServiceGroupIdentifier getServiceIdentifier() {
return this.deviceInfo.getServiceIdentifier();
@Override
public void onFailure(@Nonnull final Throwable throwable) {
timeCounter.addTimeMark();
- LOG.warn("Statistics gathering for single node {} was not successful: {}", deviceInfo.getLOGValue(),
- throwable.getMessage());
- if (LOG.isTraceEnabled()) {
- LOG.trace("Gathering for node {} failure: ", deviceInfo.getLOGValue(), throwable);
- }
calculateTimerDelay(timeCounter);
+
if (throwable instanceof ConnectionException) {
// ConnectionException is raised by StatisticsContextImpl class when the connections
// move to RIP state. In this particular case, there is no need to reschedule
// because this statistics manager should be closed soon
- LOG.warn("Node {} is no more connected, stopping the statistics collection",
+ LOG.warn("Device {} is no more connected, stopping the statistics collection",
deviceInfo.getLOGValue(),throwable);
stopScheduling(deviceInfo);
+ } else if (throwable instanceof CancellationException) {
+ LOG.info("Statistics gathering for device {} was cancelled.",
+ deviceInfo.getLOGValue());
} else {
- if (!(throwable instanceof CancellationException)) {
- LOG.warn("Unexpected error occurred during statistics collection for node {}, rescheduling " +
- "statistics collections", deviceInfo.getLOGValue(),throwable);
- }
+ LOG.warn("Unexpected error occurred during statistics collection for device {}, rescheduling " +
+ "statistics collections", deviceInfo.getLOGValue(), throwable);
+
scheduleNextPolling(deviceState, deviceInfo, statisticsContext, timeCounter);
}
}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.util;
+
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timeout;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ItemScheduler<K, V> implements AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(ItemScheduler.class);
+
+ private final HashedWheelTimer hashedWheelTimer;
+ private final Consumer<V> action;
+ private final long timeoutMillis;
+ private final long toleranceMillis;
+ private final Map<K, V> items = Collections.synchronizedMap(new HashMap<>());
+ private final Map<K, V> queue = Collections.synchronizedMap(new HashMap<>());
+ private final Object scheduleLock = new Object();
+
+ private volatile long startTime = -1;
+ private volatile Timeout runningTimeout;
+
+ /**
+ * Instantiates a new Item scheduler.
+ *
+ * @param hashedWheelTimer the hashed wheel timer
+ * @param timeoutMillis the timeout millis
+ * @param toleranceMillis the tolerance millis
+ * @param action the action
+ */
+ public ItemScheduler(final HashedWheelTimer hashedWheelTimer,
+ final long timeoutMillis,
+ final long toleranceMillis,
+ final Consumer<V> action) {
+ this.hashedWheelTimer = hashedWheelTimer;
+ this.action = action;
+ this.timeoutMillis = timeoutMillis;
+ this.toleranceMillis = toleranceMillis;
+ }
+
+ /**
+ * Start scheduler timeout if it is not already running and if there are any items scheduled
+ */
+ public void startIfNotRunning() {
+ synchronized (scheduleLock) {
+ if (Objects.nonNull(runningTimeout) || (items.isEmpty() && queue.isEmpty())) {
+ LOG.debug("Scheduler {} is already running or nothing is scheduled, skipping start.", this);
+ return;
+ }
+
+ startTime = System.currentTimeMillis();
+ LOG.debug("Scheduler {} started with configured timeout {}ms and scheduling tolerance {}ms.",
+ this, timeoutMillis, toleranceMillis);
+
+ runningTimeout = hashedWheelTimer.newTimeout((timeout) -> {
+ synchronized (scheduleLock) {
+ LOG.debug("Running configured action on {} scheduled items for scheduler {}. There are {} items left in queue.",
+ items.size(), this, queue.size());
+ items.forEach((key, item) -> action.accept(item));
+ items.clear();
+ items.putAll(queue);
+ queue.clear();
+ close();
+ }
+
+ startIfNotRunning();
+ }, timeoutMillis, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ /**
+ * Schedule item for processing
+ *
+ * @param key the item key
+ * @param item the item
+ */
+ public void add(final K key, final V item) {
+ synchronized (scheduleLock) {
+ final long currentTime = System.currentTimeMillis();
+
+ if (currentTime - toleranceMillis <= startTime) {
+ LOG.debug("Adding {} to scheduled items for scheduler {}.", key, this);
+ items.put(key, item);
+ } else {
+ LOG.debug("Adding {} to scheduling queue for scheduler {}.", key, this);
+ queue.put(key, item);
+ }
+ }
+ }
+
+ /**
+ * Remove item for processing
+ * @param key the item key
+ */
+ public void remove(final K key) {
+ synchronized (scheduleLock) {
+ LOG.debug("Removing {} from scheduled items and queue for scheduler {}", key, this);
+ items.remove(key);
+ queue.remove(key);
+
+ if (items.isEmpty() && queue.isEmpty()) {
+ close();
+ }
+ }
+ }
+
+ @Override
+ public void close() {
+ LOG.debug("Closing scheduler {} and cancelling all running tasks.", this);
+ startTime = -1;
+
+ if (Objects.nonNull(runningTimeout)) {
+ runningTimeout.cancel();
+ runningTimeout = null;
+ }
+ }
+}
@Nonnull final DeviceContext deviceContext,
final ExtensionConverterProvider extensionConverterProvider,
final ConvertorExecutor convertorExecutor) {
- Preconditions.checkArgument(rpcContext != null);
- Preconditions.checkArgument(deviceContext != null);
-
// TODO: Use multipart writer provider from device context
final MultipartWriterProvider multipartWriterProvider = MultipartWriterProviderFactory
.createDefaultProvider(deviceContext);
+++ /dev/null
-package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.config.openflow.plugin.impl.rev150327;
-
-import com.google.common.reflect.AbstractInvocationHandler;
-import com.google.common.reflect.Reflection;
-import java.lang.reflect.Method;
-import org.opendaylight.controller.config.api.osgi.WaitingServiceTracker;
-import org.opendaylight.openflowplugin.api.openflow.OpenFlowPluginProvider;
-import org.opendaylight.openflowplugin.extension.api.OpenFlowPluginExtensionRegistratorProvider;
-import org.osgi.framework.BundleContext;
-
-/**
- * @deprecated Replaced by blueprint wiring
- */
-@Deprecated
-public class OpenFlowProviderModule extends AbstractOpenFlowProviderModule {
-
- private BundleContext bundleContext;
-
- public OpenFlowProviderModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
- super(identifier, dependencyResolver);
- }
-
- public OpenFlowProviderModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.config.openflow.plugin.impl.rev150327.OpenFlowProviderModule oldModule, final java.lang.AutoCloseable oldInstance) {
- super(identifier, dependencyResolver, oldModule, oldInstance);
- }
-
- @Override
- public AutoCloseable createInstance() {
- // The service is provided via blueprint so wait for and return it here for backwards compatibility.
- String typeFilter = String.format("(type=%s)", getIdentifier().getInstanceName());
- final WaitingServiceTracker<OpenFlowPluginProvider> tracker = WaitingServiceTracker.create(
- OpenFlowPluginProvider.class, bundleContext, typeFilter);
- final OpenFlowPluginProvider openflowPluginProvider = tracker.waitForService(WaitingServiceTracker.FIVE_MINUTES);
-
- // We don't want to call close on the actual service as its life cycle is controlled by blueprint but
- // we do want to close the tracker so create a proxy to override close appropriately.
- return Reflection.newProxy(OpenFlowPluginProviderProxyInterface.class, new AbstractInvocationHandler() {
- @Override
- protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
- if (method.getName().equals("close")) {
- tracker.close();
- return null;
- } else {
- return method.invoke(openflowPluginProvider, args);
- }
- }
- });
- }
-
- public void setBundleContext(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-
- @Override
- public boolean canReuseInstance(AbstractOpenFlowProviderModule oldModule) {
- return true;
- }
-
- private static interface OpenFlowPluginProviderProxyInterface extends OpenFlowPluginProvider,
- OpenFlowPluginExtensionRegistratorProvider {
- }
-}
+++ /dev/null
-/*
-* Generated file
-*
-* Generated from: yang module name: openflow-plugin-provider-impl yang module local name: openflow-plugin-provider-impl
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Tue Mar 31 15:05:47 CEST 2015
-*
-* Do not modify this file unless it is present under src/main directory
-*/
-package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.config.openflow.plugin.impl.rev150327;
-
-import org.opendaylight.controller.config.api.DependencyResolver;
-import org.osgi.framework.BundleContext;
-
-/**
- * @deprecated Replaced by blueprint wiring
- */
-@Deprecated
-public class OpenFlowProviderModuleFactory extends AbstractOpenFlowProviderModuleFactory {
- @Override
- public OpenFlowProviderModule instantiateModule(String instanceName, DependencyResolver dependencyResolver,
- OpenFlowProviderModule oldModule, AutoCloseable oldInstance, BundleContext bundleContext) {
- OpenFlowProviderModule module = super.instantiateModule(instanceName, dependencyResolver, oldModule,
- oldInstance, bundleContext);
- module.setBundleContext(bundleContext);
- return module;
- }
-
- @Override
- public OpenFlowProviderModule instantiateModule(String instanceName, DependencyResolver dependencyResolver,
- BundleContext bundleContext) {
- OpenFlowProviderModule module = super.instantiateModule(instanceName, dependencyResolver, bundleContext);
- module.setBundleContext(bundleContext);
- return module;
- }
-}
+++ /dev/null
-module openflow-plugin-provider-impl {
- yang-version 1;
- namespace "urn:opendaylight:params:xml:ns:yang:config:openflow:plugin:impl";
- prefix "openflow-plugin-provider-impl";
-
- import config {prefix config; revision-date 2013-04-05;}
- import rpc-context { prefix rpcx; revision-date 2013-06-17; }
- import openflow-provider {prefix openflow-provider; revision-date 2015-03-31;}
- import openflow-switch-connection-provider {prefix openflow-switch-connection-provider;revision-date 2014-03-28;}
- import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
- import opendaylight-sal-binding-broker-impl { prefix sal-broker; revision-date 2013-10-28;}
- import openflowplugin-extension-registry {prefix ofp-ext-reg; revision-date 2015-04-25;}
- import opendaylight-entity-ownership-service { prefix ownership-service; revision-date 2015-08-10;}
-
- description
- "openflow-plugin-impl";
-
- revision "2015-03-27" {
- description
- "Second openflow plugin implementation.";
- }
-
- typedef non-zero-uint32-type {
- type uint32 {
- range "1..max";
- }
- }
-
- typedef non-zero-uint16-type {
- type uint16 {
- range "1..max";
- }
- }
-
- identity openflow-plugin-provider-impl {
- base config:module-type;
- config:provided-service openflow-provider:openflow-provider;
- config:provided-service ofp-ext-reg:openflow-extension-registry-provider;
- config:java-name-prefix OpenFlowProvider;
- }
-
- augment "/config:modules/config:module/config:configuration" {
- case openflow-plugin-provider-impl {
- when "/config:modules/config:module/config:type = 'openflow-plugin-provider-impl'";
-
- container data-broker {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity md-sal-binding:binding-async-data-broker;
- }
- }
- }
- container rpc-registry {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity md-sal-binding:binding-rpc-registry;
- }
- }
- }
- container notification-adapter {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity sal-broker:binding-new-notification-service;
- }
- }
- }
- container notification-publish-adapter {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity sal-broker:binding-new-notification-publish-service;
- }
- }
- }
- container entity-ownership-service {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity ownership-service:entity-ownership-service;
- }
- }
- }
- list openflow-switch-connection-provider {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity openflow-switch-connection-provider:openflow-switch-connection-provider;
- }
- }
- }
- leaf rpc-requests-quota {
- type uint32;
- default 500;
- }
- leaf switch-features-mandatory {
- type boolean;
- default false;
- }
- leaf global-notification-quota {
- type uint32;
- default 131072;
- }
- leaf is-statistics-polling-on {
- type boolean;
- default "true";
- }
- leaf is-statistics-rpc-enabled {
- status deprecated;
- description "Exposing backward compatible statistics rpcs providing result in form of async notification";
- type boolean;
- default "false";
- }
- leaf barrier-interval-timeout-limit {
- type non-zero-uint32-type;
- default 500;
- }
- leaf barrier-count-limit {
- type non-zero-uint16-type;
- default 25600;
- }
- leaf echo-reply-timeout {
- type non-zero-uint32-type;
- default 2000;
- }
- }
-
- }
-}
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import java.math.BigInteger;
-import java.net.InetSocketAddress;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.Before;
import org.junit.Test;
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;
import org.opendaylight.openflowplugin.api.openflow.device.TranslatorLibrary;
DeviceContext deviceContext;
@Mock
- TransactionChainManager txChainManager;
- @Mock
RequestContext<GetAsyncReply> requestContext;
@Mock
RequestContext<MultipartReply> requestContextMultiReply;
@Mock
ConnectionContext connectionContext;
@Mock
- DeviceState deviceState;
- @Mock
GetFeaturesOutput featuresOutput;
@Mock
DataBroker dataBroker;
verify(wTx).submit();
}
- @Test
- public void testAuxiliaryConnectionContext() {
- final ConnectionContext mockedConnectionContext = addDummyAuxiliaryConnectionContext();
- final ConnectionContext pickedConnectionContexts = deviceContext.getAuxiliaryConnectionContexts(DUMMY_COOKIE);
- assertEquals(mockedConnectionContext, pickedConnectionContexts);
- }
- @Test
- public void testRemoveAuxiliaryConnectionContext() {
- final ConnectionContext mockedConnectionContext = addDummyAuxiliaryConnectionContext();
-
- final ConnectionAdapter mockedAuxConnectionAdapter = mock(ConnectionAdapter.class);
- when(mockedConnectionContext.getConnectionAdapter()).thenReturn(mockedAuxConnectionAdapter);
-
- assertNotNull(deviceContext.getAuxiliaryConnectionContexts(DUMMY_COOKIE));
- deviceContext.removeAuxiliaryConnectionContext(mockedConnectionContext);
- assertNull(deviceContext.getAuxiliaryConnectionContexts(DUMMY_COOKIE));
- }
-
- private ConnectionContext addDummyAuxiliaryConnectionContext() {
- final ConnectionContext mockedConnectionContext = prepareConnectionContext();
- deviceContext.addAuxiliaryConnectionContext(mockedConnectionContext);
- return mockedConnectionContext;
- }
-
private ConnectionContext prepareConnectionContext() {
final ConnectionContext mockedConnectionContext = mock(ConnectionContext.class);
final FeaturesReply mockedFeaturesReply = mock(FeaturesReply.class);
assertEquals(translatorLibrary, pickedTranslatorLibrary);
}
- @Test
- public void testShutdownConnection() {
- final ConnectionAdapter mockedConnectionAdapter = mock(ConnectionAdapter.class);
- final InetSocketAddress mockRemoteAddress = InetSocketAddress.createUnresolved("odl-unit.example.org",999);
- when(mockedConnectionAdapter.getRemoteAddress()).thenReturn(mockRemoteAddress);
- when(connectionContext.getConnectionAdapter()).thenReturn(mockedConnectionAdapter);
-
- final NodeId dummyNodeId = new NodeId("dummyNodeId");
- when(deviceInfo.getNodeId()).thenReturn(dummyNodeId);
-
- final ConnectionContext mockedAuxiliaryConnectionContext = prepareConnectionContext();
- deviceContext.addAuxiliaryConnectionContext(mockedAuxiliaryConnectionContext);
- deviceContext.shutdownConnection();
- verify(connectionContext).closeConnection(true);
- }
-
@Test
public void testBarrierFieldSetGet() {
final Timeout mockedTimeout = mock(Timeout.class);
@Test
public void testOnPublished() {
- final ConnectionContext auxiliaryConnectionContext = addDummyAuxiliaryConnectionContext();
-
- final ConnectionAdapter mockedAuxConnectionAdapter = mock(ConnectionAdapter.class);
- when(auxiliaryConnectionContext.getConnectionAdapter()).thenReturn(mockedAuxConnectionAdapter);
-
final ConnectionAdapter mockedConnectionAdapter = mock(ConnectionAdapter.class);
when(connectionContext.getConnectionAdapter()).thenReturn(mockedConnectionAdapter);
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
deviceManager.close();
- verify(deviceContext).shutdownConnection();
- verify(deviceContext, Mockito.never()).close();
+ verify(deviceContext).close();
}
private static ConcurrentHashMap<DeviceInfo, DeviceContext> getContextsCollection(final DeviceManagerImpl deviceManager) throws NoSuchFieldException, IllegalAccessException {
Mockito.verify(txChain).newWriteOnlyTransaction();
Mockito.verify(writeTx).put(LogicalDatastoreType.CONFIGURATION, path, data, false);
- Mockito.verify(writeTx).submit();
+ Mockito.verify(writeTx, Mockito.never()).submit();
+ Mockito.verify(writeTx).cancel();
Mockito.verify(txChain).close();
}
public void testShuttingDown() throws Exception{
final Node data = new NodeBuilder().setId(nodeId).build();
txChainManager.writeToTransaction(LogicalDatastoreType.CONFIGURATION, path, data, false);
-
+ txChainManager.enableSubmit();
txChainManager.shuttingDown();
Mockito.verify(txChain).newWriteOnlyTransaction();
import com.google.common.util.concurrent.Futures;
import io.netty.util.HashedWheelTimer;
+import java.util.concurrent.ExecutorService;
import org.junit.Assert;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
@Mock
private ClusterSingletonServiceProvider singletonServicesProvider;
@Mock
- private EntityOwnershipService entityOwnershipService;
+ private ExecutorService executorService;
+ @Mock
+ private ClusterSingletonServiceRegistration clusterSingletonServiceRegistration;
private ContextChainHolderImpl contextChainHolder;
@Before
public void setUp() throws Exception {
- contextChainHolder = new ContextChainHolderImpl(timer);
- contextChainHolder.addManager(statisticsManager);
- contextChainHolder.addManager(rpcManager);
- contextChainHolder.addManager(deviceManager);
- contextChainHolder.addSingletonServicesProvider(singletonServicesProvider);
+ Mockito.doAnswer(invocation -> {
+ invocation.getArgumentAt(0, Runnable.class).run();
+ return null;
+ }).when(executorService).submit(Mockito.<Runnable>any());
+
+
Mockito.when(connectionContext.getDeviceInfo()).thenReturn(deviceInfo);
Mockito.when(deviceManager.createContext(connectionContext)).thenReturn(deviceContext);
Mockito.when(rpcManager.createContext(
.thenReturn(rpcContext);
Mockito.when(statisticsManager.createContext(deviceContext)).thenReturn(statisticsContext);
Mockito.when(deviceContext.makeDeviceSlave()).thenReturn(Futures.immediateFuture(null));
+ Mockito.when(deviceContext.getDeviceInfo()).thenReturn(deviceInfo);
+
+ Mockito.when(singletonServicesProvider.registerClusterSingletonService(Mockito.any()))
+ .thenReturn(clusterSingletonServiceRegistration);
+ contextChainHolder = new ContextChainHolderImpl(timer, executorService);
+ contextChainHolder.addManager(statisticsManager);
+ contextChainHolder.addManager(rpcManager);
+ contextChainHolder.addManager(deviceManager);
+ contextChainHolder.addSingletonServicesProvider(singletonServicesProvider);
}
@Test
}
@Test
- @Ignore
public void createContextChain() throws Exception {
contextChainHolder.createContextChain(connectionContext);
Mockito.verify(deviceManager).createContext(Mockito.any(ConnectionContext.class));
contextChain.isMastered(ContextChainMastershipState.INITIAL_SUBMIT);
contextChain.isMastered(ContextChainMastershipState.MASTER_ON_DEVICE);
contextChain.isMastered(ContextChainMastershipState.INITIAL_FLOW_REGISTRY_FILL);
+ contextChain.isMastered(ContextChainMastershipState.RPC_REGISTRATION);
contextChain.connectionDropped();
Mockito.verify(deviceContext).stopClusterServices();
Mockito.verify(rpcContext).stopClusterServices();
package org.opendaylight.openflowplugin.impl.lifecycle;
import com.google.common.util.concurrent.Futures;
+import java.util.concurrent.ExecutorService;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
-import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler;
import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceRemovedHandler;
import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService;
import org.opendaylight.openflowplugin.api.openflow.lifecycle.MastershipChangeListener;
@Mock
private MastershipChangeListener mastershipChangeListener;
@Mock
- private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler;
- @Mock
private DeviceRemovedHandler deviceRemovedHandler;
+ @Mock
+ private ExecutorService executorService;
private LifecycleService lifecycleService;
Mockito.when(clusterSingletonServiceProvider.registerClusterSingletonService(Mockito.any()))
.thenReturn(clusterSingletonServiceRegistration);
- lifecycleService = new LifecycleServiceImpl(mastershipChangeListener);
+ Mockito.doAnswer(invocation -> {
+ invocation.getArgumentAt(0, Runnable.class).run();
+ return null;
+ }).when(executorService).submit(Mockito.<Runnable>any());
+
+ lifecycleService = new LifecycleServiceImpl(mastershipChangeListener, executorService);
lifecycleService.registerService(
clusterSingletonServiceProvider,
deviceContext);
import static org.mockito.Mockito.when;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
assertEquals(serviceInstance,temp);
}
- //TODO: RPCServices should be removed on event from singleton service
@Test
- @Ignore
public void testClose() {
serviceClass = TestRpcService.class;
when(routedRpcReg.getServiceType()).thenReturn(serviceClass);
</goals>
<configuration>
<codeGenerators>
- <generator>
- <codeGeneratorClass>
- org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
- </codeGeneratorClass>
- <outputBaseDir>${project.build.directory}/generated-sources/config</outputBaseDir>
- <additionalConfiguration>
- <namespaceToPackage1>
- urn:opendaylight:params:xml:ns:yang:controller==org.opendaylight.controller.config.yang
- </namespaceToPackage1>
- </additionalConfiguration>
- </generator>
<generator>
<codeGeneratorClass>
org.opendaylight.mdsal.binding.maven.api.gen.plugin.CodeGeneratorImpl
+++ /dev/null
-/**
-* Generated file
-
-* Generated from: yang module name: openflow-provider-impl yang module local name: openflow-provider-impl
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Wed Apr 02 16:59:36 PDT 2014
-*
-* Do not modify this file unless it is present under src/main directory
-*/
-package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326;
-
-import java.util.Collection;
-import org.opendaylight.controller.config.api.osgi.WaitingServiceTracker;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
-import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
-import org.opendaylight.openflowjava.protocol.spi.connection.SwitchConnectionProvider;
-import org.opendaylight.openflowplugin.api.openflow.statistics.MessageCountDumper;
-import org.opendaylight.openflowplugin.extension.api.ExtensionConverterRegistrator;
-import org.opendaylight.openflowplugin.openflow.md.core.sal.OpenflowPluginProvider;
-import org.osgi.framework.BundleContext;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * @deprecated Replaced by blueprint wiring
- */
-@Deprecated
-public final class ConfigurableOpenFlowProviderModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326.AbstractConfigurableOpenFlowProviderModule {
-
- private static final Logger LOG = LoggerFactory.getLogger(ConfigurableOpenFlowProviderModule.class);
-
- private BundleContext bundleContext;
-
- /**
- * @param identifier module identifier
- * @param dependencyResolver dependency resolver
- */
- public ConfigurableOpenFlowProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
- super(identifier, dependencyResolver);
- }
-
- /**
- * @param identifier module identifier
- * @param dependencyResolver dependency resolver
- * @param oldModule old module
- * @param oldInstance old instance
- */
- public ConfigurableOpenFlowProviderModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier, org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
- ConfigurableOpenFlowProviderModule oldModule, java.lang.AutoCloseable oldInstance) {
-
- super(identifier, dependencyResolver, oldModule, oldInstance);
- }
-
- @Override
- protected void customValidation() {
- // Add custom validation for module attributes here.
- }
-
- @Override
- public AutoCloseable createInstance() {
- // The service is provided via blueprint so wait for and return it here for backwards compatibility.
- String typeFilter = String.format("(type=%s)", getIdentifier().getInstanceName());
- final WaitingServiceTracker<OpenflowPluginProvider> tracker = WaitingServiceTracker.create(
- OpenflowPluginProvider.class, bundleContext, typeFilter);
- final OpenflowPluginProvider actualService = tracker.waitForService(WaitingServiceTracker.FIVE_MINUTES);
-
- return new OpenflowPluginProvider() {
- @Override
- public void close() {
- // Don't close the actual service as its life cycle is controlled by blueprint.
- tracker.close();
- }
-
- @Override
- public void initialization() {
- actualService.initialization();
- }
-
- @Override
- public void setSwitchConnectionProviders(Collection<SwitchConnectionProvider> switchConnectionProvider) {
- actualService.setSwitchConnectionProviders(switchConnectionProvider);
- }
-
- @Override
- public MessageCountDumper getMessageCountDumper() {
- return actualService.getMessageCountDumper();
- }
-
- @Override
- public ExtensionConverterRegistrator getExtensionConverterRegistrator() {
- return actualService.getExtensionConverterRegistrator();
- }
-
- @Override
- public void setRole(OfpRole role) {
- actualService.setRole(role);
- }
-
- @Override
- public void setSkipTableFeatures(Boolean skipTableFeatures) {
- actualService.setSkipTableFeatures(skipTableFeatures);
- }
-
- @Override
- public void fireRoleChange(OfpRole newRole) {
- actualService.fireRoleChange(newRole);
- }
-
- @Override
- public void setDataBroker(DataBroker dataBroker) {
- actualService.setDataBroker(dataBroker);
- }
-
- @Override
- public void setNotificationService(NotificationProviderService notificationService) {
- actualService.setNotificationService(notificationService);
- }
-
- @Override
- public void setRpcRegistry(RpcProviderRegistry rpcRegistry) {
- actualService.setRpcRegistry(rpcRegistry);
- }
-
- @Override
- public void setEntityOwnershipService(EntityOwnershipService entityOwnershipService) {
- actualService.setEntityOwnershipService(entityOwnershipService);
- }
- };
- }
-
- public void setBundleContext(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-
- @Override
- public boolean canReuseInstance(AbstractConfigurableOpenFlowProviderModule oldModule) {
- return true;
- }
-
-}
+++ /dev/null
-/**
-* Generated file
-
-* Generated from: yang module name: openflow-provider-impl yang module local name: openflow-provider-impl
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Wed Apr 02 16:59:36 PDT 2014
-*
-* Do not modify this file unless it is present under src/main directory
-*/
-package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326;
-
-import org.opendaylight.controller.config.api.DependencyResolver;
-import org.osgi.framework.BundleContext;
-
-/**
- * @deprecated Replaced by blueprint wiring
- */
-@Deprecated
-public class ConfigurableOpenFlowProviderModuleFactory extends AbstractConfigurableOpenFlowProviderModuleFactory {
- @Override
- public ConfigurableOpenFlowProviderModule instantiateModule(String instanceName, DependencyResolver dependencyResolver,
- ConfigurableOpenFlowProviderModule oldModule, AutoCloseable oldInstance, BundleContext bundleContext) {
- ConfigurableOpenFlowProviderModule module = super.instantiateModule(instanceName, dependencyResolver, oldModule,
- oldInstance, bundleContext);
- module.setBundleContext(bundleContext);
- return module;
- }
-
- @Override
- public ConfigurableOpenFlowProviderModule instantiateModule(String instanceName, DependencyResolver dependencyResolver,
- BundleContext bundleContext) {
- ConfigurableOpenFlowProviderModule module = super.instantiateModule(instanceName, dependencyResolver, bundleContext);
- module.setBundleContext(bundleContext);
- return module;
- }
-}
+++ /dev/null
-package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326;
-
-import java.text.SimpleDateFormat;
-import java.util.List;
-
-import org.opendaylight.openflowplugin.openflow.md.core.sal.OpenflowPluginProvider;
-import org.opendaylight.openflowplugin.api.openflow.statistics.MessageCountDumper;
-import org.opendaylight.openflowplugin.api.openflow.statistics.MessageObservatory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * MsgSpyServiceModul implements and register own MsgSpyServiceRuntimeMXBean
- * which is linked to {@link MessageObservatory} from {@link OpenflowPluginProvider}
- *
- * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
- *
- */
-public class MsgSpyServiceModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326.AbstractMsgSpyServiceModule {
- private static final Logger log = LoggerFactory.getLogger(MsgSpyServiceModule.class);
-
- private static final SimpleDateFormat ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
-
- public MsgSpyServiceModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
- final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
-
- super(identifier, dependencyResolver);
- }
-
- public MsgSpyServiceModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
- final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
- final MsgSpyServiceModule oldModule, final java.lang.AutoCloseable oldInstance) {
-
- super(identifier, dependencyResolver, oldModule, oldInstance);
- }
-
- @Override
- public void customValidation() {
- // No need to validate dependencies, since all dependencies are mandatory
- // config-subsystem will perform the validation
- }
-
- @Override
- public java.lang.AutoCloseable createInstance() {
- final MessageCountDumper msg = getOpenflowPluginProviderDependency().getMessageCountDumper();
-
- /* Internal MXBean implementation -> make statMsg from dumpMessageCounst only yet */
- final MsgSpyServiceRuntimeMXBean msgSpyBean = new MsgSpyServiceRuntimeMXBean() {
-
- @Override
- public String makeMsgStatistics() {
- if (msg == null) {
- return "Message Spy Count Dumper is not avaliable.";
- }
- List<String> statList = msg.dumpMessageCounts();
-
- StringBuilder strBuilder = new StringBuilder(ft.format(System.currentTimeMillis()));
- for (String stat : statList) {
- strBuilder.append("\n").append(stat);
- }
- return strBuilder.toString();
- }
-
- @Override
- public String getMsgStatistics() {
- return makeMsgStatistics();
- }
- };
-
- /* MXBean registration */
- final MsgSpyServiceRuntimeRegistration runtimeReg =
- getRootRuntimeBeanRegistratorWrapper().register(msgSpyBean);
-
- /* Internal MsgSpyService implementation */
- final class AutoClosableMsgSpyService implements MessageCountDumper, AutoCloseable {
-
- @Override
- public void close() {
- if (runtimeReg != null) {
- try {
- runtimeReg.close();
- }
- catch (Exception e) {
- String errMsg = "Error by stop MsgSpyService.";
- log.error(errMsg, e);
- throw new IllegalStateException(errMsg, e);
- }
- }
- log.info(" Msg Stat Service consumer (instance {} turn down.)", this);
- }
-
- @Override
- public List<String> dumpMessageCounts() {
- return msg.dumpMessageCounts();
- }
- }
-
- AutoCloseable ret = new AutoClosableMsgSpyService();
- log.info("MsgStatService (instance {}) initialized.", ret);
- return ret;
- }
-
-}
+++ /dev/null
-/*
-* Generated file
-*
-* Generated from: yang module name: openflow-provider-impl yang module local name: msg-spy-service-impl
-* Generated by: org.opendaylight.controller.config.yangjmxgenerator.plugin.JMXGenerator
-* Generated at: Fri Jul 04 09:53:32 CEST 2014
-*
-* Do not modify this file unless it is present under src/main directory
-*/
-package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326;
-public class MsgSpyServiceModuleFactory extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326.AbstractMsgSpyServiceModuleFactory {
-
-}
<relativePath>parent</relativePath>
</parent>
- <groupId>org.opendaylight.openflowplugin</groupId>
<artifactId>openflowplugin-aggregator</artifactId>
<version>0.5.0-SNAPSHOT</version>
<name>openflowplugin</name> <!-- Used by Sonar to set project name -->
<module>openflowplugin-common</module>
<module>extension</module>
<module>distribution/karaf</module>
- <module>openflowplugin-controller-config</module>
<module>openflowplugin-blueprint-config</module>
- <!--
- <module>openflowplugin-it</module>
- -->
+ <!-- <module>openflowplugin-it</module> -->
<module>test-provider</module>
<module>drop-test-karaf</module>
<module>test-common</module>