Merge "Convert OF samples to use DTCL instead of DCL"
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / util / DeviceInitializationUtils.java
1 /*
2  * Copyright (c) 2016 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.util;
10
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.AsyncFunction;
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 com.google.common.util.concurrent.SettableFuture;
17 import java.math.BigInteger;
18 import java.net.InetSocketAddress;
19 import java.util.Arrays;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.Objects;
24 import java.util.concurrent.ExecutionException;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueue;
27 import org.opendaylight.openflowplugin.api.ConnectionException;
28 import org.opendaylight.openflowplugin.api.OFConstants;
29 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
30 import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
31 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
32 import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
33 import org.opendaylight.openflowplugin.api.openflow.device.MessageTranslator;
34 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
35 import org.opendaylight.openflowplugin.api.openflow.device.Xid;
36 import org.opendaylight.openflowplugin.api.openflow.device.handlers.MultiMsgCollector;
37 import org.opendaylight.openflowplugin.api.openflow.md.core.TranslatorKey;
38 import org.opendaylight.openflowplugin.impl.common.MultipartRequestInputFactory;
39 import org.opendaylight.openflowplugin.impl.common.NodeStaticReplyTranslatorUtil;
40 import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
43 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsData;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsDataBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.Capabilities;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.CapabilitiesV10;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortGrouping;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.MultipartReplyBody;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyDescCase;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyGroupFeaturesCase;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyMeterFeaturesCase;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyPortDescCase;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyTableFeaturesCase;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.desc._case.MultipartReplyDesc;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.group.features._case.MultipartReplyGroupFeatures;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.meter.features._case.MultipartReplyMeterFeatures;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.port.desc._case.MultipartReplyPortDesc;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table.features._case.MultipartReplyTableFeatures;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey;
80 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
81 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
82 import org.opendaylight.yangtools.yang.common.RpcError;
83 import org.opendaylight.yangtools.yang.common.RpcResult;
84 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
85 import org.slf4j.Logger;
86 import org.slf4j.LoggerFactory;
87
88 public class DeviceInitializationUtils {
89
90     private static final Logger LOG = LoggerFactory.getLogger(DeviceInitializationUtils.class);
91
92     private DeviceInitializationUtils() {
93         // Hiding implicit constructor
94     }
95
96     /**
97      * InitializationNodeInformation is good to call only for MASTER otherwise we will have not empty transaction
98      * for every Cluster Node (SLAVE too) and we will get race-condition by closing Connection.
99      *
100      * @param deviceContext
101      * @param switchFeaturesMandatory
102      * @param convertorExecutor
103      */
104     public static void initializeNodeInformation(final DeviceContext deviceContext, final boolean switchFeaturesMandatory, final ConvertorExecutor convertorExecutor) throws ExecutionException, InterruptedException {
105         Preconditions.checkArgument(deviceContext != null);
106         final DeviceState deviceState = Preconditions.checkNotNull(deviceContext.getDeviceState());
107         final DeviceInfo deviceInfo = deviceContext.getDeviceInfo();
108         final ConnectionContext connectionContext = Preconditions.checkNotNull(deviceContext.getPrimaryConnectionContext());
109         final short version = deviceInfo.getVersion();
110         LOG.trace("initalizeNodeInformation for node {}", deviceInfo.getNodeId());
111         final SettableFuture<Void> returnFuture = SettableFuture.<Void>create();
112         addNodeToOperDS(deviceContext, returnFuture);
113         final ListenableFuture<List<RpcResult<List<MultipartReply>>>> deviceFeaturesFuture;
114         if (OFConstants.OFP_VERSION_1_0 == version) {
115             final CapabilitiesV10 capabilitiesV10 = connectionContext.getFeatures().getCapabilitiesV10();
116
117             DeviceStateUtil.setDeviceStateBasedOnV10Capabilities(deviceState, capabilitiesV10);
118
119             deviceFeaturesFuture = createDeviceFeaturesForOF10(deviceContext);
120             // create empty tables after device description is processed
121             chainTableTrunkWriteOF10(deviceContext, deviceFeaturesFuture);
122
123             final short ofVersion = deviceInfo.getVersion();
124             final TranslatorKey translatorKey = new TranslatorKey(ofVersion, PortGrouping.class.getName());
125             final MessageTranslator<PortGrouping, FlowCapableNodeConnector> translator = deviceContext.oook()
126                     .lookupTranslator(translatorKey);
127             final BigInteger dataPathId = deviceContext.getDeviceInfo().getDatapathId();
128
129             for (final PortGrouping port : connectionContext.getFeatures().getPhyPort()) {
130                 final FlowCapableNodeConnector fcNodeConnector = translator.translate(port, deviceContext.getDeviceInfo(), null);
131
132                 final NodeConnectorId nodeConnectorId = NodeStaticReplyTranslatorUtil.nodeConnectorId(
133                         dataPathId.toString(), port.getPortNo(), ofVersion);
134                 final NodeConnectorBuilder ncBuilder = new NodeConnectorBuilder().setId(nodeConnectorId);
135                 ncBuilder.addAugmentation(FlowCapableNodeConnector.class, fcNodeConnector);
136                 ncBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class,
137                         new FlowCapableNodeConnectorStatisticsDataBuilder().build());
138                 final NodeConnector connector = ncBuilder.build();
139                 final InstanceIdentifier<NodeConnector> connectorII = deviceInfo.getNodeInstanceIdentifier().child(
140                         NodeConnector.class, connector.getKey());
141                 try {
142                     deviceContext.writeToTransaction(LogicalDatastoreType.OPERATIONAL, connectorII, connector);
143                 } catch (final Exception e) {
144                     LOG.debug("initializeNodeInformation: Failed to write node {} to DS ", deviceInfo.getNodeId().toString(),
145                             e);
146                 }
147
148             }
149         } else if (OFConstants.OFP_VERSION_1_3 == version) {
150             final Capabilities capabilities = connectionContext.getFeatures().getCapabilities();
151             LOG.debug("Setting capabilities for device {}", deviceInfo.getNodeId());
152             DeviceStateUtil.setDeviceStateBasedOnV13Capabilities(deviceState, capabilities);
153             createDeviceFeaturesForOF13(deviceContext, switchFeaturesMandatory, convertorExecutor).get();
154         } else {
155             throw new ExecutionException(new ConnectionException("Unsupported version " + version));
156         }
157
158     }
159
160     private static void addNodeToOperDS(final DeviceContext deviceContext, final SettableFuture<Void> future) {
161         Preconditions.checkArgument(deviceContext != null);
162         final NodeBuilder nodeBuilder = new NodeBuilder().setId(deviceContext.getDeviceInfo().getNodeId()).setNodeConnector(
163                 Collections.<NodeConnector>emptyList());
164         try {
165             deviceContext.writeToTransaction(LogicalDatastoreType.OPERATIONAL, deviceContext.getDeviceInfo().getNodeInstanceIdentifier(),
166                     nodeBuilder.build());
167         } catch (final Exception e) {
168             LOG.warn("addNodeToOperDS: Failed to write node {} to DS ", deviceContext.getDeviceInfo().getNodeId(), e);
169             future.cancel(true);
170         }
171     }
172
173     private static ListenableFuture<List<RpcResult<List<MultipartReply>>>> createDeviceFeaturesForOF10(
174             final DeviceContext deviceContext) {
175         final ListenableFuture<RpcResult<List<MultipartReply>>> replyDesc = getNodeStaticInfo(MultipartType.OFPMPDESC,
176                 deviceContext, deviceContext.getDeviceInfo().getNodeInstanceIdentifier(), deviceContext.getDeviceInfo().getVersion());
177
178         return Futures.allAsList(Arrays.asList(replyDesc));
179     }
180
181     private static ListenableFuture<List<RpcResult<List<MultipartReply>>>> createDeviceFeaturesForOF13(
182             final DeviceContext deviceContext, final boolean switchFeaturesMandatory, final ConvertorExecutor convertorExecutor) {
183
184         final ListenableFuture<RpcResult<List<MultipartReply>>> replyDesc = getNodeStaticInfo(MultipartType.OFPMPDESC,
185                 deviceContext, deviceContext.getDeviceInfo().getNodeInstanceIdentifier(), deviceContext.getDeviceInfo().getVersion());
186
187         //first process description reply, write data to DS and write consequent data if successful
188         return Futures.transform(replyDesc,
189                 new AsyncFunction<RpcResult<List<MultipartReply>>, List<RpcResult<List<MultipartReply>>>>() {
190                     @Override
191                     public ListenableFuture<List<RpcResult<List<MultipartReply>>>> apply(
192                             final RpcResult<List<MultipartReply>> rpcResult) throws Exception {
193
194                         translateAndWriteReply(MultipartType.OFPMPDESC, deviceContext,
195                                 deviceContext.getDeviceInfo().getNodeInstanceIdentifier(), rpcResult.getResult(), convertorExecutor);
196
197                         final ListenableFuture<RpcResult<List<MultipartReply>>> replyMeterFeature = getNodeStaticInfo(
198                                 MultipartType.OFPMPMETERFEATURES, deviceContext,
199                                 deviceContext.getDeviceInfo().getNodeInstanceIdentifier(), deviceContext.getDeviceInfo().getVersion());
200
201                         createSuccessProcessingCallback(MultipartType.OFPMPMETERFEATURES, deviceContext,
202                                 deviceContext.getDeviceInfo().getNodeInstanceIdentifier(), replyMeterFeature, convertorExecutor);
203
204                         final ListenableFuture<RpcResult<List<MultipartReply>>> replyGroupFeatures = getNodeStaticInfo(
205                                 MultipartType.OFPMPGROUPFEATURES, deviceContext,
206                                 deviceContext.getDeviceInfo().getNodeInstanceIdentifier(), deviceContext.getDeviceInfo().getVersion());
207                         createSuccessProcessingCallback(MultipartType.OFPMPGROUPFEATURES, deviceContext,
208                                 deviceContext.getDeviceInfo().getNodeInstanceIdentifier(), replyGroupFeatures, convertorExecutor);
209
210                         final ListenableFuture<RpcResult<List<MultipartReply>>> replyTableFeatures;
211
212                         if (deviceContext.isSkipTableFeatures()){
213                             replyTableFeatures = RpcResultBuilder.<List<MultipartReply>>success().buildFuture();
214                         } else {
215                             replyTableFeatures = getNodeStaticInfo(
216                                     MultipartType.OFPMPTABLEFEATURES, deviceContext,
217                                     deviceContext.getDeviceInfo().getNodeInstanceIdentifier(), deviceContext.getDeviceInfo().getVersion());
218                         }
219                         createSuccessProcessingCallback(MultipartType.OFPMPTABLEFEATURES, deviceContext,
220                                 deviceContext.getDeviceInfo().getNodeInstanceIdentifier(), replyTableFeatures, convertorExecutor);
221
222                         final ListenableFuture<RpcResult<List<MultipartReply>>> replyPortDescription = getNodeStaticInfo(
223                                 MultipartType.OFPMPPORTDESC, deviceContext, deviceContext.getDeviceInfo().getNodeInstanceIdentifier(),
224                                 deviceContext.getDeviceInfo().getVersion());
225                         createSuccessProcessingCallback(MultipartType.OFPMPPORTDESC, deviceContext,
226                                 deviceContext.getDeviceInfo().getNodeInstanceIdentifier(), replyPortDescription, convertorExecutor);
227                         if (switchFeaturesMandatory) {
228                             return Futures.allAsList(Arrays.asList(replyMeterFeature, replyGroupFeatures,
229                                     replyTableFeatures, replyPortDescription));
230                         } else {
231                             return Futures.successfulAsList(Arrays.asList(replyMeterFeature, replyGroupFeatures,
232                                     replyTableFeatures, replyPortDescription));
233                         }
234                     }
235                 });
236
237     }
238
239     static void translateAndWriteReply(final MultipartType type, final DeviceContext dContext,
240                                        final InstanceIdentifier<Node> nodeII, final Collection<MultipartReply> result,
241                                        final ConvertorExecutor convertorExecutor) {
242         try {
243             result.stream()
244                     .map(MultipartReply::getMultipartReplyBody)
245                     .forEach(multipartReplyBody -> {
246                         if (!(writeDesc(type, multipartReplyBody, dContext, nodeII)
247                                 || writeTableFeatures(type, multipartReplyBody, dContext, nodeII, convertorExecutor)
248                                 || writeMeterFeatures(type, multipartReplyBody, dContext, nodeII)
249                                 || writeGroupFeatures(type, multipartReplyBody, dContext, nodeII)
250                                 || writePortDesc(type, multipartReplyBody, dContext, nodeII))) {
251                             throw new IllegalArgumentException("Unexpected MultipartType " + type);
252                         }
253                     });
254         } catch (final Exception e) {
255             LOG.debug("translateAndWriteReply: Failed to write node {} to DS ", dContext.getDeviceInfo().getNodeId().toString(), e);
256         }
257     }
258
259     private static boolean writeDesc(final MultipartType type,
260                                      final MultipartReplyBody body,
261                                      final DeviceContext dContext,
262                                      final InstanceIdentifier<Node> nodeII) {
263         if (!MultipartType.OFPMPDESC.equals(type)) {
264             return false;
265         }
266
267         Preconditions.checkArgument(body instanceof MultipartReplyDescCase);
268         final MultipartReplyDesc replyDesc = ((MultipartReplyDescCase) body).getMultipartReplyDesc();
269         final FlowCapableNode fcNode = NodeStaticReplyTranslatorUtil.nodeDescTranslator(replyDesc,
270                 getIpAddressOf(dContext));
271         final InstanceIdentifier<FlowCapableNode> fNodeII = nodeII.augmentation(FlowCapableNode.class);
272         dContext.writeToTransaction(LogicalDatastoreType.OPERATIONAL, fNodeII, fcNode);
273         return true;
274     }
275
276     private static boolean writeTableFeatures(final MultipartType type,
277                                               final MultipartReplyBody body,
278                                               final DeviceContext dContext,
279                                               final InstanceIdentifier<Node> nodeII,
280                                               final ConvertorExecutor convertorExecutor) {
281         if (!MultipartType.OFPMPTABLEFEATURES.equals(type)) {
282             return false;
283         }
284
285         Preconditions.checkArgument(body instanceof MultipartReplyTableFeaturesCase);
286         final MultipartReplyTableFeatures tableFeaturesMP = ((MultipartReplyTableFeaturesCase) body)
287                 .getMultipartReplyTableFeatures();
288         final List<TableFeatures> tableFeatures = NodeStaticReplyTranslatorUtil
289                 .nodeTableFeatureTranslator(tableFeaturesMP, dContext.getDeviceInfo().getVersion(), convertorExecutor);
290         for (final TableFeatures tableFeature : tableFeatures) {
291             final Short tableId = tableFeature.getTableId();
292             final KeyedInstanceIdentifier<TableFeatures, TableFeaturesKey> tableFeaturesII =
293                     nodeII.augmentation(FlowCapableNode.class)
294                             .child(TableFeatures.class, new TableFeaturesKey(tableId));
295             dContext.writeToTransaction(LogicalDatastoreType.OPERATIONAL, tableFeaturesII, tableFeature);
296
297             // write parent for table statistics
298             final KeyedInstanceIdentifier<Table, TableKey> tableII =
299                     nodeII.augmentation(FlowCapableNode.class)
300                             .child(Table.class, new TableKey(tableId));
301             final TableBuilder tableBld = new TableBuilder().setId(tableId)
302                     .addAugmentation(FlowTableStatisticsData.class,
303                             new FlowTableStatisticsDataBuilder().build());
304
305             dContext.writeToTransaction(LogicalDatastoreType.OPERATIONAL, tableII, tableBld.build());
306         }
307
308         return true;
309     }
310
311     private static boolean writeMeterFeatures(final MultipartType type,
312                                               final MultipartReplyBody body,
313                                               final DeviceContext dContext,
314                                               final InstanceIdentifier<Node> nodeII) {
315         if (!MultipartType.OFPMPMETERFEATURES.equals(type)) {
316             return false;
317         }
318
319         Preconditions.checkArgument(body instanceof MultipartReplyMeterFeaturesCase);
320         final MultipartReplyMeterFeatures meterFeatures = ((MultipartReplyMeterFeaturesCase) body)
321                 .getMultipartReplyMeterFeatures();
322         final NodeMeterFeatures mFeature = NodeStaticReplyTranslatorUtil
323                 .nodeMeterFeatureTranslator(meterFeatures);
324         final InstanceIdentifier<NodeMeterFeatures> mFeatureII = nodeII
325                 .augmentation(NodeMeterFeatures.class);
326         dContext.writeToTransaction(LogicalDatastoreType.OPERATIONAL, mFeatureII, mFeature);
327         if (0L < mFeature.getMeterFeatures().getMaxMeter().getValue()) {
328             dContext.getDeviceState().setMeterAvailable(true);
329         }
330
331         return true;
332     }
333
334     private static boolean writeGroupFeatures(final MultipartType type,
335                                               final MultipartReplyBody body,
336                                               final DeviceContext dContext,
337                                               final InstanceIdentifier<Node> nodeII) {
338         if (!MultipartType.OFPMPGROUPFEATURES.equals(type)) {
339             return false;
340         }
341
342         Preconditions.checkArgument(body instanceof MultipartReplyGroupFeaturesCase);
343         final MultipartReplyGroupFeatures groupFeatures = ((MultipartReplyGroupFeaturesCase) body)
344                 .getMultipartReplyGroupFeatures();
345         final NodeGroupFeatures gFeature = NodeStaticReplyTranslatorUtil
346                 .nodeGroupFeatureTranslator(groupFeatures);
347         final InstanceIdentifier<NodeGroupFeatures> gFeatureII = nodeII
348                 .augmentation(NodeGroupFeatures.class);
349         dContext.writeToTransaction(LogicalDatastoreType.OPERATIONAL, gFeatureII, gFeature);
350
351         return true;
352     }
353
354     private static boolean writePortDesc(final MultipartType type,
355                                          final MultipartReplyBody body,
356                                          final DeviceContext dContext,
357                                          final InstanceIdentifier<Node> nodeII) {
358         if (!MultipartType.OFPMPPORTDESC.equals(type)) {
359             return false;
360         }
361
362         Preconditions.checkArgument(body instanceof MultipartReplyPortDescCase);
363         final MultipartReplyPortDesc portDesc = ((MultipartReplyPortDescCase) body)
364                 .getMultipartReplyPortDesc();
365         for (final PortGrouping port : portDesc.getPorts()) {
366             final short ofVersion = dContext.getDeviceInfo().getVersion();
367             final TranslatorKey translatorKey = new TranslatorKey(ofVersion, PortGrouping.class.getName());
368             final MessageTranslator<PortGrouping, FlowCapableNodeConnector> translator = dContext.oook()
369                     .lookupTranslator(translatorKey);
370             final FlowCapableNodeConnector fcNodeConnector = translator.translate(port, dContext.getDeviceInfo(), null);
371
372             final BigInteger dataPathId = dContext.getPrimaryConnectionContext().getFeatures()
373                     .getDatapathId();
374             final NodeConnectorId nodeConnectorId = NodeStaticReplyTranslatorUtil.nodeConnectorId(
375                     dataPathId.toString(), port.getPortNo(), ofVersion);
376             final NodeConnectorBuilder ncBuilder = new NodeConnectorBuilder().setId(nodeConnectorId);
377             ncBuilder.addAugmentation(FlowCapableNodeConnector.class, fcNodeConnector);
378
379             ncBuilder.addAugmentation(FlowCapableNodeConnectorStatisticsData.class,
380                     new FlowCapableNodeConnectorStatisticsDataBuilder().build());
381             final NodeConnector connector = ncBuilder.build();
382
383             final InstanceIdentifier<NodeConnector> connectorII = nodeII.child(NodeConnector.class,
384                     connector.getKey());
385             dContext.writeToTransaction(LogicalDatastoreType.OPERATIONAL, connectorII, connector);
386         }
387
388         return true;
389     }
390
391     private static void createEmptyFlowCapableNodeInDs(final DeviceContext deviceContext) {
392         final FlowCapableNodeBuilder flowCapableNodeBuilder = new FlowCapableNodeBuilder();
393         final InstanceIdentifier<FlowCapableNode> fNodeII = deviceContext.getDeviceInfo().getNodeInstanceIdentifier()
394                 .augmentation(FlowCapableNode.class);
395         try {
396             deviceContext.writeToTransaction(LogicalDatastoreType.OPERATIONAL, fNodeII, flowCapableNodeBuilder.build());
397         } catch (final Exception e) {
398             LOG.debug("createEmptyFlowCapableNodeInDs: Failed to write node {} to DS ", deviceContext.getDeviceInfo().getNodeId().toString(), e);
399         }
400     }
401
402     private static IpAddress getIpAddressOf(final DeviceContext deviceContext) {
403
404         final InetSocketAddress remoteAddress = deviceContext.getPrimaryConnectionContext().getConnectionAdapter()
405                 .getRemoteAddress();
406
407         if (remoteAddress == null) {
408             LOG.warn("IP address of the node {} cannot be obtained. No connection with switch.", deviceContext
409                     .getDeviceInfo().getNodeId());
410             return null;
411         }
412         LOG.info("IP address of switch is: {}", remoteAddress);
413
414         return IetfInetUtil.INSTANCE.ipAddressFor(remoteAddress.getAddress());
415     }
416
417     // FIXME : remove after ovs tableFeatures fix
418     private static void makeEmptyTables(final DeviceContext dContext, final InstanceIdentifier<Node> nodeII,
419                                         final Short nrOfTables) {
420         if (LOG.isDebugEnabled()) {
421             LOG.debug("About to create {} empty tables.", nrOfTables);
422         }
423         for (int i = 0; i < nrOfTables; i++) {
424             final short tId = (short) i;
425             final InstanceIdentifier<Table> tableII = nodeII.augmentation(FlowCapableNode.class).child(Table.class,
426                     new TableKey(tId));
427             final TableBuilder tableBuilder = new TableBuilder().setId(tId).addAugmentation(
428                     FlowTableStatisticsData.class, new FlowTableStatisticsDataBuilder().build());
429
430             try {
431                 dContext.writeToTransaction(LogicalDatastoreType.OPERATIONAL, tableII, tableBuilder.build());
432             } catch (final Exception e) {
433                 LOG.debug("makeEmptyTables: Failed to write node {} to DS ", dContext.getDeviceInfo().getNodeId().toString(), e);
434             }
435
436         }
437     }
438
439     static void createSuccessProcessingCallback(final MultipartType type, final DeviceContext deviceContext,
440                                                 final InstanceIdentifier<Node> nodeII,
441                                                 final ListenableFuture<RpcResult<List<MultipartReply>>> requestContextFuture,
442                                                 final ConvertorExecutor convertorExecutor) {
443         Futures.addCallback(requestContextFuture, new FutureCallback<RpcResult<List<MultipartReply>>>() {
444             @Override
445             public void onSuccess(final RpcResult<List<MultipartReply>> rpcResult) {
446                 final List<MultipartReply> result = rpcResult.getResult();
447                 if (result != null) {
448                     LOG.info("Static node {} info: {} collected", deviceContext.getDeviceInfo().getNodeId(), type);
449                     translateAndWriteReply(type, deviceContext, nodeII, result, convertorExecutor);
450                 } else {
451                     for (RpcError rpcError : rpcResult.getErrors()) {
452                         LOG.info("Failed to retrieve static node {} info: {}", type, rpcError.getMessage());
453                         if (LOG.isTraceEnabled() && Objects.nonNull(rpcError.getCause())) {
454                             LOG.trace("Detailed error:", rpcError.getCause());
455                         }
456                     }
457                     if (MultipartType.OFPMPTABLEFEATURES.equals(type)) {
458                         makeEmptyTables(deviceContext, nodeII, deviceContext.getPrimaryConnectionContext()
459                                 .getFeatures().getTables());
460                     }
461                 }
462             }
463
464             @Override
465             public void onFailure(final Throwable throwable) {
466                 LOG.info("Request of type {} for static info of node {} failed.", type, nodeII);
467             }
468         });
469     }
470
471     private static ListenableFuture<RpcResult<List<MultipartReply>>> getNodeStaticInfo(final MultipartType type,
472                                                                                        final DeviceContext deviceContext,
473                                                                                        final InstanceIdentifier<Node> nodeII,
474                                                                                        final short version) {
475
476         final OutboundQueue queue = deviceContext.getPrimaryConnectionContext().getOutboundQueueProvider();
477
478         final Long reserved = deviceContext.getDeviceInfo().reserveXidForDeviceMessage();
479         final RequestContext<List<MultipartReply>> requestContext = new AbstractRequestContext<List<MultipartReply>>(
480                 reserved) {
481             @Override
482             public void close() {
483                 //NOOP
484             }
485         };
486
487         final Xid xid = requestContext.getXid();
488
489         LOG.trace("Hooking xid {} to device context - precaution.", reserved);
490
491         final MultiMsgCollector multiMsgCollector = deviceContext.getMultiMsgCollector(requestContext);
492         queue.commitEntry(xid.getValue(),
493                 MultipartRequestInputFactory.makeMultipartRequestInput(xid.getValue(), version, type),
494                 new FutureCallback<OfHeader>() {
495                     @Override
496                     public void onSuccess(final OfHeader ofHeader) {
497                         if (ofHeader instanceof MultipartReply) {
498                             final MultipartReply multipartReply = (MultipartReply) ofHeader;
499                             multiMsgCollector.addMultipartMsg(multipartReply);
500                         } else if (null != ofHeader) {
501                             LOG.info("Unexpected response type received {}.", ofHeader.getClass());
502                         } else {
503                             multiMsgCollector.endCollecting();
504                             LOG.info("Response received is null.");
505                         }
506                     }
507
508                     @Override
509                     public void onFailure(final Throwable t) {
510                         LOG.info("Fail response from OutboundQueue for multipart type {}.", type);
511                         final RpcResult<List<MultipartReply>> rpcResult = RpcResultBuilder
512                                 .<List<MultipartReply>>failed().build();
513                         requestContext.setResult(rpcResult);
514                         if (MultipartType.OFPMPTABLEFEATURES.equals(type)) {
515                             makeEmptyTables(deviceContext, nodeII, deviceContext.getPrimaryConnectionContext()
516                                     .getFeatures().getTables());
517                         }
518                         requestContext.close();
519                     }
520                 });
521
522         return requestContext.getFuture();
523     }
524
525     static void chainTableTrunkWriteOF10(final DeviceContext deviceContext,
526                                          final ListenableFuture<List<RpcResult<List<MultipartReply>>>> deviceFeaturesFuture) {
527
528         try {
529             if (LOG.isTraceEnabled()) {
530                 LOG.trace("Waiting for protocol version 1.0");
531             }
532             List<RpcResult<List<MultipartReply>>> results = deviceFeaturesFuture.get();
533             boolean allSucceeded = true;
534             for (final RpcResult<List<MultipartReply>> rpcResult : results) {
535                 allSucceeded &= rpcResult.isSuccessful();
536             }
537             if (allSucceeded) {
538                 if (LOG.isDebugEnabled()) {
539                     LOG.debug("Creating empty flow capable node: {}", deviceContext.getDeviceInfo().getLOGValue());
540                 }
541                 createEmptyFlowCapableNodeInDs(deviceContext);
542                 if (LOG.isDebugEnabled()) {
543                     LOG.debug("Creating empty tables for {}", deviceContext.getDeviceInfo().getLOGValue());
544                 }
545                 makeEmptyTables(deviceContext, deviceContext.getDeviceInfo().getNodeInstanceIdentifier(),
546                         deviceContext.getPrimaryConnectionContext().getFeatures().getTables());
547             }
548         } catch (InterruptedException | ExecutionException e) {
549             LOG.warn("Error occurred in preparation node {} for protocol 1.0", deviceContext.getDeviceInfo().getLOGValue());
550             if (LOG.isTraceEnabled()) {
551                 LOG.trace("Error for node {} : ", deviceContext.getDeviceInfo().getLOGValue(), e);
552             }
553         }
554     }
555 }