a28bbf726f4e89c5cc90a5a30133cc53c9ed3f9c
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / device / DeviceManagerImpl.java
1 /**
2  * Copyright (c) 2015, 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 package org.opendaylight.openflowplugin.impl.device;
9
10 import com.google.common.util.concurrent.CheckedFuture;
11 import com.google.common.util.concurrent.FutureCallback;
12 import com.google.common.util.concurrent.Futures;
13 import io.netty.util.HashedWheelTimer;
14 import io.netty.util.internal.ConcurrentSet;
15 import java.util.Optional;
16 import java.util.Set;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.ConcurrentMap;
19 import java.util.concurrent.ScheduledThreadPoolExecutor;
20 import java.util.concurrent.TimeUnit;
21 import javax.annotation.Nonnull;
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
24 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
27 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueueHandlerRegistration;
28 import org.opendaylight.openflowplugin.api.openflow.OFPContext;
29 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
30 import org.opendaylight.openflowplugin.api.openflow.connection.OutboundQueueProvider;
31 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
32 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
33 import org.opendaylight.openflowplugin.api.openflow.device.DeviceManager;
34 import org.opendaylight.openflowplugin.api.openflow.device.TranslatorLibrary;
35 import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageSpy;
36 import org.opendaylight.openflowplugin.extension.api.ExtensionConverterProviderKeeper;
37 import org.opendaylight.openflowplugin.extension.api.core.extension.ExtensionConverterProvider;
38 import org.opendaylight.openflowplugin.impl.connection.OutboundQueueProviderImpl;
39 import org.opendaylight.openflowplugin.impl.device.initialization.DeviceInitializerProvider;
40 import org.opendaylight.openflowplugin.impl.device.listener.OpenflowProtocolListenerFullImpl;
41 import org.opendaylight.openflowplugin.impl.services.sal.SalRoleServiceImpl;
42 import org.opendaylight.openflowplugin.impl.util.DeviceInitializationUtil;
43 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemovedBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdatedBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.provider.config.rev160510.OpenflowProviderConfig;
51 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 /**
56  *
57  */
58 public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProviderKeeper {
59
60     private static final Logger LOG = LoggerFactory.getLogger(DeviceManagerImpl.class);
61     private static final int SPY_RATE = 10;
62
63     private final OpenflowProviderConfig config;
64     private final DataBroker dataBroker;
65     private final DeviceInitializerProvider deviceInitializerProvider;
66     private final ConvertorExecutor convertorExecutor;
67     private final ConcurrentMap<DeviceInfo, DeviceContext> deviceContexts = new ConcurrentHashMap<>();
68     private final Set<KeyedInstanceIdentifier<Node, NodeKey>> notificationCreateNodeSend = new ConcurrentSet<>();
69     private final NotificationPublishService notificationPublishService;
70     private final MessageSpy messageSpy;
71     private final HashedWheelTimer hashedWheelTimer;
72     private TranslatorLibrary translatorLibrary;
73     private ExtensionConverterProvider extensionConverterProvider;
74     private ScheduledThreadPoolExecutor spyPool;
75
76     public DeviceManagerImpl(@Nonnull final OpenflowProviderConfig config,
77                              @Nonnull final DataBroker dataBroker,
78                              @Nonnull final MessageSpy messageSpy,
79                              @Nonnull final NotificationPublishService notificationPublishService,
80                              @Nonnull final HashedWheelTimer hashedWheelTimer,
81                              @Nonnull final ConvertorExecutor convertorExecutor,
82                              @Nonnull final DeviceInitializerProvider deviceInitializerProvider) {
83         this.config = config;
84         this.dataBroker = dataBroker;
85         this.deviceInitializerProvider = deviceInitializerProvider;
86         this.convertorExecutor = convertorExecutor;
87         this.hashedWheelTimer = hashedWheelTimer;
88         this.spyPool = new ScheduledThreadPoolExecutor(1);
89         this.notificationPublishService = notificationPublishService;
90         this.messageSpy = messageSpy;
91         DeviceInitializationUtil.makeEmptyNodes(dataBroker);
92     }
93
94     @Override
95     public TranslatorLibrary oook() {
96         return translatorLibrary;
97     }
98
99     @Override
100     public void setTranslatorLibrary(final TranslatorLibrary translatorLibrary) {
101         this.translatorLibrary = translatorLibrary;
102     }
103
104     @Override
105     public void close() {
106         deviceContexts.values().forEach(OFPContext::close);
107         deviceContexts.clear();
108         Optional.ofNullable(spyPool).ifPresent(ScheduledThreadPoolExecutor::shutdownNow);
109         spyPool = null;
110
111     }
112
113     @Override
114     public void initialize() {
115         spyPool.scheduleAtFixedRate(messageSpy, SPY_RATE, SPY_RATE, TimeUnit.SECONDS);
116     }
117
118     @Override
119     public void setExtensionConverterProvider(final ExtensionConverterProvider extensionConverterProvider) {
120         this.extensionConverterProvider = extensionConverterProvider;
121     }
122
123     @Override
124     public ExtensionConverterProvider getExtensionConverterProvider() {
125         return extensionConverterProvider;
126     }
127
128     @Override
129     public CheckedFuture<Void, TransactionCommitFailedException> removeDeviceFromOperationalDS(final KeyedInstanceIdentifier<Node, NodeKey> ii) {
130         final WriteTransaction delWtx = dataBroker.newWriteOnlyTransaction();
131         delWtx.delete(LogicalDatastoreType.OPERATIONAL, ii);
132         final CheckedFuture<Void, TransactionCommitFailedException> delFuture = delWtx.submit();
133
134         Futures.addCallback(delFuture, new FutureCallback<Void>() {
135             @Override
136             public void onSuccess(final Void result) {
137                 if (LOG.isDebugEnabled()) {
138                     LOG.debug("Delete Node {} was successful", ii);
139                 }
140             }
141
142             @Override
143             public void onFailure(@Nonnull final Throwable t) {
144                 LOG.warn("Delete node {} failed with exception {}", ii, t);
145             }
146         });
147
148         return delFuture;
149     }
150
151     public DeviceContext createContext(@Nonnull final ConnectionContext connectionContext) {
152
153         LOG.info("ConnectionEvent: Device connected to controller, Device:{}, NodeId:{}",
154                 connectionContext.getConnectionAdapter().getRemoteAddress(),
155                 connectionContext.getDeviceInfo().getNodeId());
156
157         connectionContext.getConnectionAdapter().setPacketInFiltering(true);
158
159         final OutboundQueueProvider outboundQueueProvider
160                 = new OutboundQueueProviderImpl(connectionContext.getDeviceInfo().getVersion());
161
162         connectionContext.setOutboundQueueProvider(outboundQueueProvider);
163         final OutboundQueueHandlerRegistration<OutboundQueueProvider> outboundQueueHandlerRegistration =
164                 connectionContext.getConnectionAdapter().registerOutboundQueueHandler(
165                         outboundQueueProvider,
166                         config.getBarrierCountLimit().getValue(),
167                         TimeUnit.MILLISECONDS.toNanos(config.getBarrierIntervalTimeoutLimit().getValue()));
168         connectionContext.setOutboundQueueHandleRegistration(outboundQueueHandlerRegistration);
169
170
171         final DeviceContext deviceContext = new DeviceContextImpl(
172                 connectionContext,
173                 dataBroker,
174                 messageSpy,
175                 translatorLibrary,
176                 convertorExecutor,
177                 config.isSkipTableFeatures(),
178                 hashedWheelTimer,
179                 config.isUseSingleLayerSerialization(),
180                 deviceInitializerProvider,
181                 config.isEnableFlowRemovedNotification(),
182                 config.isSwitchFeaturesMandatory());
183
184         deviceContext.setSalRoleService(new SalRoleServiceImpl(deviceContext, deviceContext));
185         ((ExtensionConverterProviderKeeper) deviceContext).setExtensionConverterProvider(extensionConverterProvider);
186         deviceContext.setNotificationPublishService(notificationPublishService);
187
188         deviceContexts.put(connectionContext.getDeviceInfo(), deviceContext);
189         updatePacketInRateLimiters();
190
191         final OpenflowProtocolListenerFullImpl messageListener = new OpenflowProtocolListenerFullImpl(
192                 connectionContext.getConnectionAdapter(), deviceContext);
193
194         connectionContext.getConnectionAdapter().setMessageListener(messageListener);
195         connectionContext.getConnectionAdapter().setAlienMessageListener(messageListener);
196
197         return deviceContext;
198     }
199
200     private void updatePacketInRateLimiters() {
201         synchronized (deviceContexts) {
202             final int deviceContextsSize = deviceContexts.size();
203             if (deviceContextsSize > 0) {
204                 long freshNotificationLimit = config.getGlobalNotificationQuota() / deviceContextsSize;
205                 if (freshNotificationLimit < 100) {
206                     freshNotificationLimit = 100;
207                 }
208                 if (LOG.isDebugEnabled()) {
209                     LOG.debug("fresh notification limit = {}", freshNotificationLimit);
210                 }
211                 for (final DeviceContext deviceContext : deviceContexts.values()) {
212                     deviceContext.updatePacketInRateLimit(freshNotificationLimit);
213                 }
214             }
215         }
216     }
217
218     @Override
219     public void onDeviceRemoved(final DeviceInfo deviceInfo) {
220         deviceContexts.remove(deviceInfo);
221         if (LOG.isDebugEnabled()) {
222             LOG.debug("Device context removed for node {}", deviceInfo.getLOGValue());
223         }
224         if (deviceContexts.size() > 0) {
225             this.updatePacketInRateLimiters();
226         }
227     }
228
229     @Override
230     public void sendNodeRemovedNotification(@Nonnull final KeyedInstanceIdentifier<Node, NodeKey> instanceIdentifier) {
231         if (notificationCreateNodeSend.remove(instanceIdentifier)) {
232             NodeRemovedBuilder builder = new NodeRemovedBuilder();
233             builder.setNodeRef(new NodeRef(instanceIdentifier));
234             LOG.info("Publishing node removed notification for {}", instanceIdentifier.firstKeyOf(Node.class).getId());
235             notificationPublishService.offerNotification(builder.build());
236         }
237     }
238
239     @Override
240     public void sendNodeAddedNotification(@Nonnull final KeyedInstanceIdentifier<Node, NodeKey> instanceIdentifier) {
241         if (!notificationCreateNodeSend.contains(instanceIdentifier)) {
242             notificationCreateNodeSend.add(instanceIdentifier);
243             final NodeId id = instanceIdentifier.firstKeyOf(Node.class).getId();
244             NodeUpdatedBuilder builder = new NodeUpdatedBuilder();
245             builder.setId(id);
246             builder.setNodeRef(new NodeRef(instanceIdentifier));
247             LOG.info("Publishing node added notification for {}", id);
248             notificationPublishService.offerNotification(builder.build());
249         }
250     }
251 }