Close ReadTransactions
[openflowplugin.git] / applications / forwardingrules-manager / src / main / java / org / opendaylight / openflowplugin / applications / frm / impl / ForwardingRulesManagerImpl.java
1 /**
2  * Copyright (c) 2014, 2017 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.applications.frm.impl;
10
11 import com.google.common.annotations.VisibleForTesting;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import java.util.Objects;
15 import java.util.Optional;
16 import java.util.concurrent.ExecutionException;
17 import java.util.concurrent.atomic.AtomicLong;
18 import javax.annotation.Nonnull;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
23 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
24 import org.opendaylight.openflowplugin.api.openflow.configuration.ConfigurationService;
25 import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeServiceManager;
26 import org.opendaylight.openflowplugin.applications.frm.FlowNodeReconciliation;
27 import org.opendaylight.openflowplugin.applications.frm.ForwardingRulesCommiter;
28 import org.opendaylight.openflowplugin.applications.frm.ForwardingRulesManager;
29 import org.opendaylight.openflowplugin.applications.frm.ForwardingRulesProperty;
30 import org.opendaylight.openflowplugin.applications.frm.NodeConfigurator;
31 import org.opendaylight.openflowplugin.applications.frm.nodeconfigurator.NodeConfiguratorImpl;
32 import org.opendaylight.openflowplugin.applications.frm.recovery.OpenflowServiceRecoveryHandler;
33 import org.opendaylight.openflowplugin.applications.reconciliation.NotificationRegistration;
34 import org.opendaylight.openflowplugin.applications.reconciliation.ReconciliationManager;
35 import org.opendaylight.serviceutils.srm.RecoverableListener;
36 import org.opendaylight.serviceutils.srm.ServiceRecoveryRegistry;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.onf.bundle.service.rev170124.SalBundleService;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.arbitrator.reconcile.service.rev180227.ArbitratorReconcileService;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.forwardingrules.manager.config.rev160511.ForwardingRulesManagerConfig;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.app.frm.reconciliation.service.rev180227.FrmReconciliationService;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.rf.state.rev170713.ResultState;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.SalTableService;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 /**
57  * forwardingrules-manager org.opendaylight.openflowplugin.applications.frm.impl
58  *
59  * <p>
60  * Manager and middle point for whole module. It contains ActiveNodeHolder and
61  * provide all RPC services.
62  *
63  */
64 public class ForwardingRulesManagerImpl implements ForwardingRulesManager {
65     private static final Logger LOG = LoggerFactory.getLogger(ForwardingRulesManagerImpl.class);
66
67     static final int STARTUP_LOOP_TICK = 500;
68     static final int STARTUP_LOOP_MAX_RETRIES = 8;
69     private static final int FRM_RECONCILIATION_PRIORITY = Integer.getInteger("frm.reconciliation.priority", 1);
70     private static final String SERVICE_NAME = "FRM";
71
72     private final AtomicLong txNum = new AtomicLong();
73     private final DataBroker dataService;
74     private final SalFlowService salFlowService;
75     private final SalGroupService salGroupService;
76     private final SalMeterService salMeterService;
77     private final SalTableService salTableService;
78     private final ClusterSingletonServiceProvider clusterSingletonServiceProvider;
79     private final SalBundleService salBundleService;
80     private final AutoCloseable configurationServiceRegistration;
81     private final MastershipChangeServiceManager mastershipChangeServiceManager;
82     private final RpcProviderRegistry rpcRegistry;
83     private ForwardingRulesCommiter<Flow> flowListener;
84     private ForwardingRulesCommiter<Group> groupListener;
85     private ForwardingRulesCommiter<Meter> meterListener;
86     private ForwardingRulesCommiter<TableFeatures> tableListener;
87     private FlowNodeReconciliation nodeListener;
88     private NotificationRegistration reconciliationNotificationRegistration;
89     private FlowNodeConnectorInventoryTranslatorImpl flowNodeConnectorInventoryTranslatorImpl;
90     private DeviceMastershipManager deviceMastershipManager;
91     private final ReconciliationManager reconciliationManager;
92     private DevicesGroupRegistry devicesGroupRegistry;
93     private NodeConfigurator nodeConfigurator;
94     private ArbitratorReconcileService arbitratorReconciliationManager;
95     private boolean disableReconciliation;
96     private boolean staleMarkingEnabled;
97     private int reconciliationRetryCount;
98     private boolean isBundleBasedReconciliationEnabled;
99     private final OpenflowServiceRecoveryHandler openflowServiceRecoveryHandler;
100     private final ServiceRecoveryRegistry serviceRecoveryRegistry;
101
102     public ForwardingRulesManagerImpl(final DataBroker dataBroker, final RpcProviderRegistry rpcRegistry,
103                                       final ForwardingRulesManagerConfig config,
104                                       final MastershipChangeServiceManager mastershipChangeServiceManager,
105                                       final ClusterSingletonServiceProvider clusterSingletonService,
106                                       final ConfigurationService configurationService,
107                                       final ReconciliationManager reconciliationManager,
108                                       final OpenflowServiceRecoveryHandler openflowServiceRecoveryHandler,
109                                       final ServiceRecoveryRegistry serviceRecoveryRegistry) {
110         disableReconciliation = config.isDisableReconciliation();
111         staleMarkingEnabled = config.isStaleMarkingEnabled();
112         reconciliationRetryCount = config.getReconciliationRetryCount();
113         isBundleBasedReconciliationEnabled = config.isBundleBasedReconciliationEnabled();
114         this.configurationServiceRegistration = configurationService.registerListener(this);
115         this.dataService = Preconditions.checkNotNull(dataBroker, "DataBroker can not be null!");
116         this.clusterSingletonServiceProvider = Preconditions.checkNotNull(clusterSingletonService,
117                 "ClusterSingletonService provider can not be null");
118         this.reconciliationManager = reconciliationManager;
119         this.rpcRegistry = rpcRegistry;
120         this.mastershipChangeServiceManager = mastershipChangeServiceManager;
121
122         Preconditions.checkArgument(rpcRegistry != null, "RpcProviderRegistry can not be null !");
123
124         this.salFlowService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalFlowService.class),
125                 "RPC SalFlowService not found.");
126         this.salGroupService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalGroupService.class),
127                 "RPC SalGroupService not found.");
128         this.salMeterService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalMeterService.class),
129                 "RPC SalMeterService not found.");
130         this.salTableService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalTableService.class),
131                 "RPC SalTableService not found.");
132         this.salBundleService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalBundleService.class),
133                 "RPC SalBundlService not found.");
134         this.openflowServiceRecoveryHandler = Preconditions.checkNotNull(openflowServiceRecoveryHandler,
135                 "Openflow service recovery handler cannot be null");
136         this.serviceRecoveryRegistry = Preconditions.checkNotNull(serviceRecoveryRegistry,
137                 "Service recovery registry cannot be null");
138         this.arbitratorReconciliationManager = Preconditions
139                 .checkNotNull(rpcRegistry.getRpcService(ArbitratorReconcileService.class),
140                         "ArbitratorReconciliationManager can not be null!");
141     }
142
143     @Override
144     public void start() {
145         nodeConfigurator = new NodeConfiguratorImpl();
146         this.devicesGroupRegistry = new DevicesGroupRegistry();
147
148         this.nodeListener = new FlowNodeReconciliationImpl(this, dataService, SERVICE_NAME, FRM_RECONCILIATION_PRIORITY,
149                 ResultState.DONOTHING);
150         if (this.isReconciliationDisabled()) {
151             LOG.debug("Reconciliation is disabled by user");
152         } else {
153             this.reconciliationNotificationRegistration = reconciliationManager.registerService(this.nodeListener);
154             LOG.debug("Reconciliation is enabled by user and successfully registered to the reconciliation framework");
155         }
156         this.deviceMastershipManager = new DeviceMastershipManager(clusterSingletonServiceProvider, this.nodeListener,
157                 dataService, mastershipChangeServiceManager);
158         this.deviceMastershipManager.setRoutedRpcReg(rpcRegistry.addRoutedRpcImplementation(
159                 FrmReconciliationService.class, new FrmReconciliationServiceImpl(this)));
160         flowNodeConnectorInventoryTranslatorImpl = new FlowNodeConnectorInventoryTranslatorImpl(dataService);
161
162         this.flowListener = new FlowForwarder(this, dataService);
163         this.groupListener = new GroupForwarder(this, dataService);
164         this.meterListener = new MeterForwarder(this, dataService);
165         this.tableListener = new TableForwarder(this, dataService);
166         LOG.info("ForwardingRulesManager has started successfully.");
167     }
168
169     @Override
170     public void close() throws Exception {
171         configurationServiceRegistration.close();
172
173         if (this.flowListener != null) {
174             this.flowListener.close();
175             this.flowListener = null;
176         }
177         if (this.groupListener != null) {
178             this.groupListener.close();
179             this.groupListener = null;
180         }
181         if (this.meterListener != null) {
182             this.meterListener.close();
183             this.meterListener = null;
184         }
185         if (this.tableListener != null) {
186             this.tableListener.close();
187             this.tableListener = null;
188         }
189         if (this.nodeListener != null) {
190             this.nodeListener.close();
191             this.nodeListener = null;
192         }
193         if (deviceMastershipManager != null) {
194             deviceMastershipManager.close();
195         }
196         if (this.reconciliationNotificationRegistration != null) {
197             this.reconciliationNotificationRegistration.close();
198             this.reconciliationNotificationRegistration = null;
199         }
200     }
201
202     @Override
203     public ReadOnlyTransaction getReadTransaction() {
204         return dataService.newReadOnlyTransaction();
205     }
206
207     @Override
208     public String getNewTransactionId() {
209         return "DOM-" + txNum.getAndIncrement();
210     }
211
212     @Override
213     public boolean isNodeActive(InstanceIdentifier<FlowCapableNode> ident) {
214         return deviceMastershipManager.isNodeActive(ident.firstKeyOf(Node.class).getId());
215     }
216
217     @Override
218     public boolean checkNodeInOperationalDataStore(InstanceIdentifier<FlowCapableNode> ident) {
219         boolean result = false;
220         InstanceIdentifier<Node> nodeIid = ident.firstIdentifierOf(Node.class);
221         try (ReadOnlyTransaction transaction = dataService.newReadOnlyTransaction()) {
222             ListenableFuture<com.google.common.base.Optional<Node>> future = transaction
223                 .read(LogicalDatastoreType.OPERATIONAL, nodeIid);
224             com.google.common.base.Optional<Node> optionalDataObject = future.get();
225             if (optionalDataObject.isPresent()) {
226                 result = true;
227             } else {
228                 LOG.debug("{}: Failed to read {}", Thread.currentThread().getStackTrace()[1], nodeIid);
229             }
230         } catch (ExecutionException | InterruptedException e) {
231             LOG.warn("Failed to read {} ", nodeIid, e);
232         }
233
234         return result;
235     }
236
237     @Override
238     public SalFlowService getSalFlowService() {
239         return salFlowService;
240     }
241
242     @Override
243     public SalGroupService getSalGroupService() {
244         return salGroupService;
245     }
246
247     @Override
248     public SalMeterService getSalMeterService() {
249         return salMeterService;
250     }
251
252     @Override
253     public SalTableService getSalTableService() {
254         return salTableService;
255     }
256
257     @Override
258     public DevicesGroupRegistry getDevicesGroupRegistry() {
259         return this.devicesGroupRegistry;
260     }
261
262     @Override
263     public SalBundleService getSalBundleService() {
264         return salBundleService;
265     }
266
267     @Override
268     public ForwardingRulesCommiter<Flow> getFlowCommiter() {
269         return flowListener;
270     }
271
272     @Override
273     public ForwardingRulesCommiter<Group> getGroupCommiter() {
274         return groupListener;
275     }
276
277     @Override
278     public ForwardingRulesCommiter<Meter> getMeterCommiter() {
279         return meterListener;
280     }
281
282     @Override
283     public ForwardingRulesCommiter<TableFeatures> getTableFeaturesCommiter() {
284         return tableListener;
285     }
286
287     @Override
288     public ArbitratorReconcileService getArbitratorReconciliationManager() {
289         return arbitratorReconciliationManager;
290     }
291
292     @Override
293     public boolean isReconciliationDisabled() {
294         return disableReconciliation;
295     }
296
297     @Override
298     public boolean isStaleMarkingEnabled() {
299         return staleMarkingEnabled;
300     }
301
302     @Override
303     public int getReconciliationRetryCount() {
304         return reconciliationRetryCount;
305     }
306
307     @Override
308     public void addRecoverableListener(RecoverableListener recoverableListener) {
309         serviceRecoveryRegistry.addRecoverableListener(openflowServiceRecoveryHandler.buildServiceRegistryKey(),
310                 recoverableListener);
311     }
312
313     @Override
314     public FlowNodeConnectorInventoryTranslatorImpl getFlowNodeConnectorInventoryTranslatorImpl() {
315         return flowNodeConnectorInventoryTranslatorImpl;
316     }
317
318     @Override
319     public NodeConfigurator getNodeConfigurator() {
320         return nodeConfigurator;
321     }
322
323     public FlowNodeReconciliation getNodeListener() {
324         return nodeListener;
325     }
326
327     @Override
328     public boolean isBundleBasedReconciliationEnabled() {
329         return isBundleBasedReconciliationEnabled;
330     }
331
332     @Override
333     public boolean isNodeOwner(InstanceIdentifier<FlowCapableNode> ident) {
334         return Objects.nonNull(ident) && deviceMastershipManager.isDeviceMastered(ident.firstKeyOf(Node.class).getId());
335     }
336
337     @VisibleForTesting
338     public void setDeviceMastershipManager(final DeviceMastershipManager deviceMastershipManager) {
339         this.deviceMastershipManager = deviceMastershipManager;
340     }
341
342     @Override
343     public void onPropertyChanged(@Nonnull final String propertyName, @Nonnull final String propertyValue) {
344         Optional.ofNullable(ForwardingRulesProperty.forValue(propertyName)).ifPresent(forwardingRulesProperty -> {
345             switch (forwardingRulesProperty) {
346                 case DISABLE_RECONCILIATION:
347                     disableReconciliation = Boolean.valueOf(propertyValue);
348                     break;
349                 case STALE_MARKING_ENABLED:
350                     staleMarkingEnabled = Boolean.valueOf(propertyValue);
351                     break;
352                 case RECONCILIATION_RETRY_COUNT:
353                     reconciliationRetryCount = Integer.parseInt(propertyValue);
354                     break;
355                 case BUNDLE_BASED_RECONCILIATION_ENABLED:
356                     isBundleBasedReconciliationEnabled = Boolean.valueOf(propertyValue);
357                     break;
358                 default:
359                     LOG.warn("No forwarding rule property found.");
360                     break;
361             }
362         });
363     }
364 }