Merge "Remove old drop-test module and files."
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / device / initialization / OF13DeviceInitializer.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.device.initialization;
10
11 import com.google.common.base.Function;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.AsyncFunction;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.Objects;
20 import java.util.Optional;
21 import java.util.concurrent.Future;
22 import java.util.stream.Collectors;
23 import javax.annotation.Nonnull;
24 import javax.annotation.Nullable;
25 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
26 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
27 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
28 import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
29 import org.opendaylight.openflowplugin.impl.common.MultipartReplyTranslatorUtil;
30 import org.opendaylight.openflowplugin.impl.datastore.MultipartWriterProvider;
31 import org.opendaylight.openflowplugin.impl.services.multilayer.MultiLayerMultipartCollectorService;
32 import org.opendaylight.openflowplugin.impl.services.singlelayer.SingleLayerMultipartCollectorService;
33 import org.opendaylight.openflowplugin.impl.util.DeviceInitializationUtil;
34 import org.opendaylight.openflowplugin.impl.util.DeviceStateUtil;
35 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterFeatures;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.MultipartReply;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.Capabilities;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
41 import org.opendaylight.yangtools.yang.common.RpcResult;
42 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 public class OF13DeviceInitializer extends AbstractDeviceInitializer {
47
48     private static final Logger LOG = LoggerFactory.getLogger(OF13DeviceInitializer.class);
49
50     @Override
51     protected Future<Void> initializeNodeInformation(@Nonnull final DeviceContext deviceContext,
52                                                      final boolean switchFeaturesMandatory,
53                                                      @Nullable final MultipartWriterProvider multipartWriterProvider,
54                                                      @Nullable final ConvertorExecutor convertorExecutor) {
55         final ConnectionContext connectionContext = Preconditions.checkNotNull(deviceContext.getPrimaryConnectionContext());
56         final DeviceState deviceState = Preconditions.checkNotNull(deviceContext.getDeviceState());
57         final DeviceInfo deviceInfo = Preconditions.checkNotNull(deviceContext.getDeviceInfo());
58         final Capabilities capabilities = connectionContext.getFeatures().getCapabilities();
59         LOG.debug("Setting capabilities for device {}", deviceInfo.getLOGValue());
60         DeviceStateUtil.setDeviceStateBasedOnV13Capabilities(deviceState, capabilities);
61
62         // First process description reply, write data to DS and write consequent data if successful
63         return  Futures.transform(
64             requestMultipart(MultipartType.OFPMPDESC, deviceContext),
65             (AsyncFunction<RpcResult<List<OfHeader>>, Void>) input -> {
66                 translateAndWriteResult(
67                     MultipartType.OFPMPDESC,
68                     input.getResult(),
69                     deviceContext,
70                     multipartWriterProvider,
71                     convertorExecutor);
72
73                 final List<ListenableFuture<RpcResult<List<OfHeader>>>> futures = new ArrayList<>();
74                 futures.add(requestAndProcessMultipart(MultipartType.OFPMPMETERFEATURES, deviceContext, multipartWriterProvider, convertorExecutor));
75                 futures.add(requestAndProcessMultipart(MultipartType.OFPMPGROUPFEATURES, deviceContext, multipartWriterProvider, convertorExecutor));
76                 futures.add(requestAndProcessMultipart(MultipartType.OFPMPTABLEFEATURES, deviceContext, multipartWriterProvider, convertorExecutor));
77                 futures.add(requestAndProcessMultipart(MultipartType.OFPMPPORTDESC, deviceContext, multipartWriterProvider, convertorExecutor));
78
79                 return Futures.transform(
80                     (switchFeaturesMandatory ? Futures.allAsList(futures) : Futures.successfulAsList(futures)),
81                     new Function<List<RpcResult<List<OfHeader>>>, Void>() {
82                         @Nullable
83                         @Override
84                         public Void apply(@Nullable final List<RpcResult<List<OfHeader>>> input) {
85                             LOG.info("Static node {} successfully finished collecting", deviceContext.getDeviceInfo().getLOGValue());
86                             return null;
87                         }
88                     });
89             });
90
91     }
92
93     /**
94      * Request multipart of specified type and then run some processing on it
95      * @param type multipart type
96      * @param deviceContext device context
97      * @param multipartWriterProvider multipart writer provider
98      * @param convertorExecutor convertor executor
99      * @return list of multipart messages unified to parent interface
100      */
101     private static ListenableFuture<RpcResult<List<OfHeader>>> requestAndProcessMultipart(final MultipartType type,
102                                                                                           final DeviceContext deviceContext,
103                                                                                           final MultipartWriterProvider multipartWriterProvider,
104                                                                                           @Nullable final ConvertorExecutor convertorExecutor) {
105         final ListenableFuture<RpcResult<List<OfHeader>>> rpcResultListenableFuture =
106             MultipartType.OFPMPTABLEFEATURES.equals(type) && deviceContext.isSkipTableFeatures()
107                 ? RpcResultBuilder.<List<OfHeader>>success().buildFuture()
108                 : requestMultipart(type, deviceContext);
109
110         createCallback(type, rpcResultListenableFuture, deviceContext, multipartWriterProvider, convertorExecutor);
111         return rpcResultListenableFuture;
112     }
113
114     /**
115      * Inject callback ti future for specified multipart type. This callback will translate and write
116      * result of multipart messages
117      * @param type multipart type
118      * @param future multipart collection future
119      * @param deviceContext device context
120      * @param multipartWriterProvider multipart writer provider
121      * @param convertorExecutor convertor executor
122      */
123     private static void createCallback(final MultipartType type,
124                                        final ListenableFuture<RpcResult<List<OfHeader>>> future,
125                                        final DeviceContext deviceContext,
126                                        @Nullable final MultipartWriterProvider multipartWriterProvider,
127                                        @Nullable final ConvertorExecutor convertorExecutor) {
128         Futures.addCallback(future, new FutureCallback<RpcResult<List<OfHeader>>>() {
129             @Override
130             public void onSuccess(final RpcResult<List<OfHeader>> result) {
131                 if (Objects.nonNull(result.getResult())) {
132                     LOG.info("Static node {} info: {} collected", deviceContext.getDeviceInfo().getLOGValue(), type);
133                     translateAndWriteResult(
134                         type,
135                         result.getResult(),
136                         deviceContext,
137                         multipartWriterProvider,
138                         convertorExecutor);
139                 } else {
140                     result.getErrors().forEach(rpcError -> {
141                         LOG.warn("Failed to retrieve static node {} info: {}", type, rpcError.getMessage());
142
143                         if (LOG.isTraceEnabled() && Objects.nonNull(rpcError.getCause())) {
144                             LOG.trace("Detailed error:", rpcError.getCause());
145                         }
146                     });
147
148                     // If table features are disabled or returned nothing, at least make empty tables
149                     if (MultipartType.OFPMPTABLEFEATURES.equals(type)) {
150                         DeviceInitializationUtil.makeEmptyTables(
151                             deviceContext,
152                             deviceContext.getDeviceInfo(),
153                             deviceContext.getPrimaryConnectionContext().getFeatures().getTables());
154                     }
155                 }
156             }
157
158             @Override
159             public void onFailure(@Nonnull final Throwable t) {
160                 LOG.warn("Request of type {} for static info of node {} failed.", type, deviceContext.getDeviceInfo().getLOGValue());
161             }
162         });
163     }
164
165     /**
166      * Translate and write multipart messages from OpenflowJava
167      * @param type multipart type
168      * @param result multipart messages
169      * @param deviceContext device context
170      * @param multipartWriterProvider multipart writer provider
171      * @param convertorExecutor convertor executor
172      */
173     private static void translateAndWriteResult(final MultipartType type,
174                                                 final List<OfHeader> result,
175                                                 final DeviceContext deviceContext,
176                                                 @Nullable final MultipartWriterProvider multipartWriterProvider,
177                                                 @Nullable final ConvertorExecutor convertorExecutor) {
178         if (Objects.nonNull(result)) {
179             try {
180                 result.forEach(reply -> {
181                     // First, translate collected data to proper openflowplugin representation
182                     MultipartReplyTranslatorUtil
183                         .translate(
184                             reply,
185                             deviceContext.getDeviceInfo(),
186                             convertorExecutor,
187                             deviceContext.oook())
188                         .ifPresent(translatedReply -> {
189                             // If we collected meter features, check if we have support for meters
190                             // and pass this information to device context
191                             if (MultipartType.OFPMPMETERFEATURES.equals(type) &&
192                                 translatedReply instanceof MeterFeatures) {
193                                 final MeterFeatures meterFeatures = (MeterFeatures) translatedReply;
194
195                                 if (meterFeatures.getMaxMeter().getValue() > 0) {
196                                     deviceContext.getDeviceState().setMeterAvailable(true);
197                                 }
198                             }
199
200                             // Now. try to write translated collected features
201                             Optional.ofNullable(multipartWriterProvider)
202                                 .flatMap(provider -> provider.lookup(type))
203                                 .ifPresent(writer -> writer.write(translatedReply, false));
204                         });
205                 });
206             } catch (final Exception e) {
207                 LOG.warn("Failed to write node {} to DS ", deviceContext.getDeviceInfo().getLOGValue(), e);
208             }
209         } else {
210             LOG.warn("Failed to write node {} to DS because we failed to gather device info.",
211                 deviceContext.getDeviceInfo().getLOGValue());
212         }
213     }
214
215     /**
216      * Send request to device and unify different possible reply types from OpenflowJava to common parent interface
217      * @param multipartType multipart type
218      * @param deviceContext device context
219      * @return unified replies
220      */
221     private static ListenableFuture<RpcResult<List<OfHeader>>> requestMultipart(final MultipartType multipartType,
222                                                                                 final DeviceContext deviceContext) {
223         if (deviceContext.canUseSingleLayerSerialization()) {
224             final SingleLayerMultipartCollectorService service =
225                 new SingleLayerMultipartCollectorService(deviceContext, deviceContext);
226
227             return Futures.transform(service.handleServiceCall(multipartType), new Function<RpcResult<List<MultipartReply>>, RpcResult<List<OfHeader>>>() {
228                 @Nullable
229                 @Override
230                 public RpcResult<List<OfHeader>> apply(final RpcResult<List<MultipartReply>> input) {
231                     if (Objects.isNull(input.getResult()) && input.isSuccessful()) {
232                         final List<OfHeader> temp = null;
233                         return RpcResultBuilder.success(temp).build();
234                     }
235
236                     return input.isSuccessful()
237                         ? RpcResultBuilder.success(input
238                         .getResult()
239                         .stream()
240                         .map(reply -> (OfHeader) reply)
241                         .collect(Collectors.toList()))
242                         .build()
243                         : RpcResultBuilder.<List<OfHeader>>failed()
244                         .withRpcErrors(input.getErrors())
245                         .build();
246                 }
247             });
248         }
249
250         final MultiLayerMultipartCollectorService service =
251             new MultiLayerMultipartCollectorService(deviceContext, deviceContext);
252
253         return Futures.transform(service.handleServiceCall(multipartType), new Function<RpcResult<List<org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply>>, RpcResult<List<OfHeader>>>() {
254             @Nullable
255             @Override
256             public RpcResult<List<OfHeader>> apply(final RpcResult<List<org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply>> input) {
257                 if (Objects.isNull(input.getResult()) && input.isSuccessful()) {
258                     final List<OfHeader> temp = null;
259                     return RpcResultBuilder.success(temp).build();
260                 }
261
262                 return input.isSuccessful()
263                     ? RpcResultBuilder.success(input
264                     .getResult()
265                     .stream()
266                     .map(reply -> (OfHeader) reply)
267                     .collect(Collectors.toList()))
268                     .build()
269                     : RpcResultBuilder.<List<OfHeader>>failed()
270                     .withRpcErrors(input.getErrors())
271                     .build();
272             }
273         });
274     }
275
276 }