BUG-5464,5954: making table features configurable for the Li plugin.
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / OpenFlowPluginProviderImpl.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.openflowplugin.impl;
10
11
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 java.lang.management.ManagementFactory;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.concurrent.SynchronousQueue;
23 import java.util.concurrent.ThreadPoolExecutor;
24 import java.util.concurrent.TimeUnit;
25 import javax.annotation.Nonnull;
26 import javax.management.InstanceAlreadyExistsException;
27 import javax.management.MBeanRegistrationException;
28 import javax.management.MBeanServer;
29 import javax.management.MalformedObjectNameException;
30 import javax.management.NotCompliantMBeanException;
31 import javax.management.ObjectName;
32 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
33 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
34 import org.opendaylight.controller.md.sal.binding.api.NotificationService;
35 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
36 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
37 import org.opendaylight.openflowjava.protocol.spi.connection.SwitchConnectionProvider;
38 import org.opendaylight.openflowplugin.api.openflow.OpenFlowPluginProvider;
39 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionManager;
40 import org.opendaylight.openflowplugin.api.openflow.device.DeviceManager;
41 import org.opendaylight.openflowplugin.api.openflow.role.RoleManager;
42 import org.opendaylight.openflowplugin.api.openflow.rpc.RpcManager;
43 import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsManager;
44 import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageIntelligenceAgency;
45 import org.opendaylight.openflowplugin.extension.api.ExtensionConverterProviderKeeper;
46 import org.opendaylight.openflowplugin.extension.api.ExtensionConverterRegistrator;
47 import org.opendaylight.openflowplugin.extension.api.OpenFlowPluginExtensionRegistratorProvider;
48 import org.opendaylight.openflowplugin.extension.api.core.extension.ExtensionConverterManager;
49 import org.opendaylight.openflowplugin.impl.connection.ConnectionManagerImpl;
50 import org.opendaylight.openflowplugin.impl.device.DeviceManagerImpl;
51 import org.opendaylight.openflowplugin.impl.role.RoleManagerImpl;
52 import org.opendaylight.openflowplugin.impl.rpc.RpcManagerImpl;
53 import org.opendaylight.openflowplugin.impl.statistics.StatisticsManagerImpl;
54 import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.MessageIntelligenceAgencyImpl;
55 import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.MessageIntelligenceAgencyMXBean;
56 import org.opendaylight.openflowplugin.impl.util.TranslatorLibraryUtil;
57 import org.opendaylight.openflowplugin.openflow.md.core.ThreadPoolLoggingExecutor;
58 import org.opendaylight.openflowplugin.openflow.md.core.extension.ExtensionConverterManagerImpl;
59 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorManager;
60 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorManagerFactory;
61 import org.opendaylight.openflowplugin.openflow.md.core.session.OFSessionUtil;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65 public class OpenFlowPluginProviderImpl implements OpenFlowPluginProvider, OpenFlowPluginExtensionRegistratorProvider {
66
67     private static final Logger LOG = LoggerFactory.getLogger(OpenFlowPluginProviderImpl.class);
68     private static final MessageIntelligenceAgency messageIntelligenceAgency = new MessageIntelligenceAgencyImpl();
69     private static final int TICKS_PER_WHEEL = 500;
70     private static final long TICK_DURATION = 10; // 0.5 sec.
71
72     private final HashedWheelTimer hashedWheelTimer = new HashedWheelTimer(TICK_DURATION, TimeUnit.MILLISECONDS, TICKS_PER_WHEEL);
73
74     private final int rpcRequestsQuota;
75     private final long globalNotificationQuota;
76     private final ConvertorManager convertorManager;
77     private long barrierInterval;
78     private int barrierCountLimit;
79     private long echoReplyTimeout;
80     private DeviceManager deviceManager;
81     private RoleManager roleManager;
82     private RpcManager rpcManager;
83     private RpcProviderRegistry rpcProviderRegistry;
84     private StatisticsManager statisticsManager;
85     private ConnectionManager connectionManager;
86     private NotificationService notificationProviderService;
87     private NotificationPublishService notificationPublishService;
88     private ExtensionConverterManager extensionConverterManager;
89     private DataBroker dataBroker;
90     private Collection<SwitchConnectionProvider> switchConnectionProviders;
91     private boolean switchFeaturesMandatory = false;
92     private boolean isStatisticsPollingOff = false;
93     private boolean isStatisticsRpcEnabled;
94     private boolean isNotificationFlowRemovedOff = false;
95     private boolean skipTableFeatures = true;
96
97     private final ThreadPoolExecutor threadPool;
98     private ClusterSingletonServiceProvider singletonServicesProvider;
99
100     public OpenFlowPluginProviderImpl(final long rpcRequestsQuota,
101                                       final long globalNotificationQuota,
102                                       final int threadPoolMinThreads,
103                                       final int threadPoolMaxThreads,
104                                       final long threadPoolTimeout) {
105         Preconditions.checkArgument(rpcRequestsQuota > 0 && rpcRequestsQuota <= Integer.MAX_VALUE, "rpcRequestQuota has to be in range <1,%s>", Integer.MAX_VALUE);
106         this.rpcRequestsQuota = (int) rpcRequestsQuota;
107         this.globalNotificationQuota = Preconditions.checkNotNull(globalNotificationQuota);
108
109         // Creates a thread pool that creates new threads as needed, but will reuse previously
110         // constructed threads when they are available.
111         // Threads that have not been used for x seconds are terminated and removed from the cache.
112         threadPool = new ThreadPoolLoggingExecutor(
113                 Preconditions.checkNotNull(threadPoolMinThreads),
114                 Preconditions.checkNotNull(threadPoolMaxThreads),
115                 Preconditions.checkNotNull(threadPoolTimeout), TimeUnit.SECONDS,
116                 new SynchronousQueue<>(), "ofppool");
117         convertorManager = ConvertorManagerFactory.createDefaultManager();
118     }
119
120     @Override
121     public boolean isStatisticsPollingOff() {
122         return isStatisticsPollingOff;
123     }
124
125     @Override
126     public void setIsStatisticsPollingOff(final boolean isStatisticsPollingOff) {
127         this.isStatisticsPollingOff = isStatisticsPollingOff;
128     }
129
130     private void startSwitchConnections() {
131         final List<ListenableFuture<Boolean>> starterChain = new ArrayList<>(switchConnectionProviders.size());
132         for (final SwitchConnectionProvider switchConnectionPrv : switchConnectionProviders) {
133             switchConnectionPrv.setSwitchConnectionHandler(connectionManager);
134             final ListenableFuture<Boolean> isOnlineFuture = switchConnectionPrv.startup();
135             starterChain.add(isOnlineFuture);
136         }
137
138         final ListenableFuture<List<Boolean>> srvStarted = Futures.allAsList(starterChain);
139         Futures.addCallback(srvStarted, new FutureCallback<List<Boolean>>() {
140             @Override
141             public void onSuccess(final List<Boolean> result) {
142                 LOG.info("All switchConnectionProviders are up and running ({}).",
143                         result.size());
144             }
145
146             @Override
147             public void onFailure(@Nonnull final Throwable t) {
148                 LOG.warn("Some switchConnectionProviders failed to start.", t);
149             }
150         });
151     }
152
153     @Override
154     public boolean isSwitchFeaturesMandatory() {
155         return switchFeaturesMandatory;
156     }
157
158     @Override
159     public void setBarrierCountLimit(final int barrierCountLimit) {
160         this.barrierCountLimit = barrierCountLimit;
161     }
162
163     @Override
164     public void setBarrierInterval(final long barrierTimeoutLimit) {
165         this.barrierInterval = barrierTimeoutLimit;
166     }
167
168     @Override
169     public void setEchoReplyTimeout(final long echoReplyTimeout) {
170         this.echoReplyTimeout = echoReplyTimeout;
171     }
172
173     @Override
174     public void setNotificationFlowRemovedOff(boolean isNotificationFlowRemovedOff) {
175         this.isNotificationFlowRemovedOff = isNotificationFlowRemovedOff;
176     }
177
178     @Override
179     public void setClusteringSingletonServicesProvider(ClusterSingletonServiceProvider singletonServicesProvider) {
180         this.singletonServicesProvider = singletonServicesProvider;
181     }
182
183     @Override
184     public void setSkipTableFeatures(final boolean skipTableFeatures){
185             this.skipTableFeatures = skipTableFeatures;
186     }
187
188     @Override
189     public void setSwitchFeaturesMandatory(final boolean switchFeaturesMandatory) {
190         this.switchFeaturesMandatory = switchFeaturesMandatory;
191     }
192
193     public static MessageIntelligenceAgency getMessageIntelligenceAgency() {
194         return OpenFlowPluginProviderImpl.messageIntelligenceAgency;
195     }
196
197     @Override
198     public void setSwitchConnectionProviders(final Collection<SwitchConnectionProvider> switchConnectionProviders) {
199         this.switchConnectionProviders = switchConnectionProviders;
200     }
201
202     @Override
203     public void setDataBroker(final DataBroker dataBroker) {
204         this.dataBroker = dataBroker;
205     }
206
207     @Override
208     public void setRpcProviderRegistry(final RpcProviderRegistry rpcProviderRegistry) {
209         this.rpcProviderRegistry = rpcProviderRegistry;
210     }
211
212     @Override
213     public void initialize() {
214         Preconditions.checkNotNull(dataBroker, "missing data broker");
215         Preconditions.checkNotNull(rpcProviderRegistry, "missing RPC provider registry");
216         Preconditions.checkNotNull(notificationProviderService, "missing notification provider service");
217         Preconditions.checkNotNull(singletonServicesProvider, "missing singleton services provider");
218
219         extensionConverterManager = new ExtensionConverterManagerImpl();
220         // TODO: copied from OpenFlowPluginProvider (Helium) misusesing the old way of distributing extension converters
221         // TODO: rewrite later!
222         OFSessionUtil.getSessionManager().setExtensionConverterProvider(extensionConverterManager);
223
224         connectionManager = new ConnectionManagerImpl(echoReplyTimeout, threadPool);
225
226         registerMXBean(messageIntelligenceAgency);
227
228         deviceManager = new DeviceManagerImpl(dataBroker,
229                 globalNotificationQuota,
230                 switchFeaturesMandatory,
231                 barrierInterval,
232                 barrierCountLimit,
233                 getMessageIntelligenceAgency(),
234                 isNotificationFlowRemovedOff,
235                 singletonServicesProvider,
236                 notificationPublishService,
237                 hashedWheelTimer,
238                 convertorManager,
239                 skipTableFeatures);
240
241         ((ExtensionConverterProviderKeeper) deviceManager).setExtensionConverterProvider(extensionConverterManager);
242
243         rpcManager = new RpcManagerImpl(rpcProviderRegistry, rpcRequestsQuota, extensionConverterManager, convertorManager, notificationPublishService);
244         roleManager = new RoleManagerImpl(dataBroker, hashedWheelTimer);
245         statisticsManager = new StatisticsManagerImpl(rpcProviderRegistry, isStatisticsPollingOff, hashedWheelTimer, convertorManager);
246
247         /* Initialization Phase ordering - OFP Device Context suite */
248         // CM -> DM -> SM -> RPC -> Role -> DM
249         connectionManager.setDeviceConnectedHandler(deviceManager);
250         deviceManager.setDeviceInitializationPhaseHandler(statisticsManager);
251         statisticsManager.setDeviceInitializationPhaseHandler(rpcManager);
252         rpcManager.setDeviceInitializationPhaseHandler(roleManager);
253         roleManager.setDeviceInitializationPhaseHandler(deviceManager);
254
255         /* Termination Phase ordering - OFP Device Context suite */
256         deviceManager.setDeviceTerminationPhaseHandler(rpcManager);
257         rpcManager.setDeviceTerminationPhaseHandler(statisticsManager);
258         statisticsManager.setDeviceTerminationPhaseHandler(roleManager);
259         roleManager.setDeviceTerminationPhaseHandler(deviceManager);
260
261         rpcManager.setStatisticsRpcEnabled(isStatisticsRpcEnabled);
262
263         TranslatorLibraryUtil.injectBasicTranslatorLibrary(deviceManager, convertorManager);
264         deviceManager.initialize();
265
266         startSwitchConnections();
267     }
268
269     @Override
270     public void update(Map<String,Object> props) {
271         LOG.debug("Update managed properties = {}", props.toString());
272         if(deviceManager != null && props.containsKey("notification-flow-removed-off")) {
273             deviceManager.setIsNotificationFlowRemovedOff(Boolean.valueOf(props.get("notification-flow-removed-off").toString()));
274         }
275         if(deviceManager != null && props.containsKey("skip-table-features")) {
276             deviceManager.setSkipTableFeatures(Boolean.valueOf(props.get("skip-table-features").toString()));
277         }
278     }
279
280     private static void registerMXBean(final MessageIntelligenceAgency messageIntelligenceAgency) {
281         final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
282         try {
283             final String pathToMxBean = String.format("%s:type=%s",
284                     MessageIntelligenceAgencyMXBean.class.getPackage().getName(),
285                     MessageIntelligenceAgencyMXBean.class.getSimpleName());
286             final ObjectName name = new ObjectName(pathToMxBean);
287             mbs.registerMBean(messageIntelligenceAgency, name);
288         } catch (MalformedObjectNameException
289                 | NotCompliantMBeanException
290                 | MBeanRegistrationException
291                 | InstanceAlreadyExistsException e) {
292             LOG.warn("Error registering MBean {}", e);
293         }
294     }
295
296     @Override
297     public void setNotificationProviderService(final NotificationService notificationProviderService) {
298         this.notificationProviderService = notificationProviderService;
299     }
300
301     @Override
302     public void setNotificationPublishService(final NotificationPublishService notificationPublishProviderService) {
303         this.notificationPublishService = notificationPublishProviderService;
304     }
305
306     @Override
307     public ExtensionConverterRegistrator getExtensionConverterRegistrator() {
308         return extensionConverterManager;
309     }
310
311     @Override
312     public void setIsStatisticsRpcEnabled(final boolean isStatisticsRpcEnabled) {
313         this.isStatisticsRpcEnabled = isStatisticsRpcEnabled;
314     }
315
316     @Override
317     public void close() throws Exception {
318         //TODO: consider wrapping each manager into try-catch
319         deviceManager.close();
320         rpcManager.close();
321         statisticsManager.close();
322
323         // TODO: needs to close org.opendaylight.openflowplugin.impl.role.OpenflowOwnershipListener after RoleContexts are down
324         // TODO: must not be executed prior to all living RoleContexts have been closed (via closing living DeviceContexts)
325         roleManager.close();
326
327         // Manually shutdown all remaining running threads in pool
328         threadPool.shutdown();
329     }
330 }