2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.openflowplugin.impl;
11 import com.google.common.annotations.VisibleForTesting;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import io.netty.util.HashedWheelTimer;
17 import io.netty.util.Timeout;
18 import io.netty.util.TimerTask;
20 import java.util.concurrent.ConcurrentHashMap;
21 import java.util.concurrent.TimeUnit;
22 import javax.annotation.Nonnull;
23 import javax.annotation.Nullable;
24 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
25 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
26 import org.opendaylight.openflowplugin.api.openflow.device.DeviceManager;
27 import org.opendaylight.openflowplugin.api.openflow.lifecycle.DeviceContextChangeListener;
28 import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleConductor;
29 import org.opendaylight.openflowplugin.api.openflow.lifecycle.RoleChangeListener;
30 import org.opendaylight.openflowplugin.api.openflow.lifecycle.ServiceChangeListener;
31 import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsManager;
32 import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageIntelligenceAgency;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
40 public final class LifecycleConductorImpl implements LifecycleConductor, RoleChangeListener, DeviceContextChangeListener {
42 private static final Logger LOG = LoggerFactory.getLogger(LifecycleConductorImpl.class);
43 private static final int TICKS_PER_WHEEL = 500;
44 private static final long TICK_DURATION = 10; // 0.5 sec.
46 private final HashedWheelTimer hashedWheelTimer = new HashedWheelTimer(TICK_DURATION, TimeUnit.MILLISECONDS, TICKS_PER_WHEEL);
47 private DeviceManager deviceManager;
48 private final MessageIntelligenceAgency messageIntelligenceAgency;
49 private ConcurrentHashMap<NodeId, ServiceChangeListener> serviceChangeListeners = new ConcurrentHashMap<>();
50 private StatisticsManager statisticsManager;
52 public LifecycleConductorImpl(final MessageIntelligenceAgency messageIntelligenceAgency) {
53 Preconditions.checkNotNull(messageIntelligenceAgency);
54 this.messageIntelligenceAgency = messageIntelligenceAgency;
57 public void setSafelyDeviceManager(final DeviceManager deviceManager) {
58 if (this.deviceManager == null) {
59 this.deviceManager = deviceManager;
63 public void setSafelyStatisticsManager(final StatisticsManager statisticsManager) {
64 if (this.statisticsManager == null) {
65 this.statisticsManager = statisticsManager;
69 public void addOneTimeListenerWhenServicesChangesDone(final ServiceChangeListener manager, final NodeId nodeId){
70 LOG.debug("Listener {} for service change for node {} registered.", manager, nodeId);
71 serviceChangeListeners.put(nodeId, manager);
75 void notifyServiceChangeListeners(final NodeId nodeId, final boolean success){
76 if (serviceChangeListeners.size() == 0) {
79 LOG.debug("Notifying registered listeners for service change, no. of listeners {}", serviceChangeListeners.size());
80 for (final Map.Entry<NodeId, ServiceChangeListener> nodeIdServiceChangeListenerEntry : serviceChangeListeners.entrySet()) {
81 if (nodeIdServiceChangeListenerEntry.getKey().equals(nodeId)) {
82 LOG.debug("Listener {} for service change for node {} was notified. Success was set on {}", nodeIdServiceChangeListenerEntry.getValue(), nodeId, success);
83 nodeIdServiceChangeListenerEntry.getValue().servicesChangeDone(nodeId, success);
84 serviceChangeListeners.remove(nodeId);
90 public void roleInitializationDone(final NodeId nodeId, final boolean success) {
92 LOG.warn("Initialization phase for node {} in role context was NOT successful, closing connection.", nodeId);
93 closeConnection(nodeId);
95 LOG.info("initialization phase for node {} in role context was successful, continuing to next context.", nodeId);
99 public void closeConnection(final NodeId nodeId) {
100 LOG.debug("Close connection called for node {}", nodeId);
101 final DeviceContext deviceContext = getDeviceContext(nodeId);
102 if (null != deviceContext) {
103 deviceContext.shutdownConnection();
108 public void roleChangeOnDevice(final NodeId nodeId, final boolean success, final OfpRole newRole, final boolean initializationPhase) {
110 final DeviceContext deviceContext = getDeviceContext(nodeId);
112 if (null == deviceContext) {
113 LOG.warn("Something went wrong, device context for nodeId: {} doesn't exists");
117 LOG.warn("Role change to {} in role context for node {} was NOT successful, closing connection", newRole, nodeId);
118 closeConnection(nodeId);
120 if (initializationPhase) {
121 LOG.debug("Initialization phase skipping starting services.");
125 LOG.info("Role change to {} in role context for node {} was successful, starting/stopping services.", newRole, nodeId);
127 if (OfpRole.BECOMEMASTER.equals(newRole)) {
128 statisticsManager.startScheduling(nodeId);
130 statisticsManager.stopScheduling(nodeId);
133 final ListenableFuture<Void> onClusterRoleChange = deviceContext.onClusterRoleChange(null, newRole);
134 Futures.addCallback(onClusterRoleChange, new FutureCallback<Void>() {
136 public void onSuccess(@Nullable final Void aVoid) {
137 LOG.info("Starting/Stopping services for node {} was successful", nodeId);
138 if (newRole.equals(OfpRole.BECOMESLAVE)) notifyServiceChangeListeners(nodeId, true);
142 public void onFailure(final Throwable throwable) {
143 LOG.warn("Starting/Stopping services for node {} was NOT successful, closing connection", nodeId);
144 closeConnection(nodeId);
150 public MessageIntelligenceAgency getMessageIntelligenceAgency() {
151 return messageIntelligenceAgency;
155 public DeviceContext getDeviceContext(final NodeId nodeId){
156 return deviceManager.getDeviceContextFromNodeId(nodeId);
159 public Short gainVersionSafely(final NodeId nodeId) {
160 return (null != getDeviceContext(nodeId)) ? getDeviceContext(nodeId).getPrimaryConnectionContext().getFeatures().getVersion() : null;
163 public Timeout newTimeout(@Nonnull TimerTask task, long delay, @Nonnull TimeUnit unit) {
164 return hashedWheelTimer.newTimeout(task, delay, unit);
167 public ConnectionContext.CONNECTION_STATE gainConnectionStateSafely(final NodeId nodeId){
168 return (null != getDeviceContext(nodeId)) ? getDeviceContext(nodeId).getPrimaryConnectionContext().getConnectionState() : null;
171 public Long reserveXidForDeviceMessage(final NodeId nodeId){
172 return null != getDeviceContext(nodeId) ? getDeviceContext(nodeId).reserveXidForDeviceMessage() : null;
176 public void deviceStartInitializationDone(final NodeId nodeId, final boolean success) {
178 LOG.warn("Initialization phase for node {} in device context was NOT successful, closing connection.", nodeId);
179 closeConnection(nodeId);
181 LOG.info("initialization phase for node {} in device context was successful. Continuing to next context.", nodeId);
186 public void deviceInitializationDone(final NodeId nodeId, final boolean success) {
188 LOG.warn("Initialization phase for node {} in device context was NOT successful, closing connection.", nodeId);
189 closeConnection(nodeId);
191 LOG.info("initialization phase for node {} in device context was successful. All phases initialized OK.", nodeId);
196 public boolean isServiceChangeListenersEmpty() {
197 return this.serviceChangeListeners.isEmpty();