PostHandshakeNodeProducer help class
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / device / PostHandshakeNodeProducer.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.device;
10
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import com.google.common.util.concurrent.SettableFuture;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.concurrent.ConcurrentHashMap;
22 import java.util.concurrent.Future;
23 import javax.annotation.Nonnull;
24 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
25 import org.opendaylight.openflowplugin.api.openflow.device.XidGenerator;
26 import org.opendaylight.openflowplugin.impl.common.MultipartRequestInputFactory;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.Counter32;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeatures;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.NodeGroupFeaturesBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.statistics.rev131111.group.features.GroupFeaturesBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.Chaining;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.ChainingChecks;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupAll;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupCapability;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupFf;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupIndirect;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupSelect;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupType;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.SelectLiveness;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.SelectWeight;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeatures;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.NodeMeterFeaturesBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.statistics.rev131111.nodes.node.MeterFeaturesBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBand;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBandDrop;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBandDscpRemark;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterBurst;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterCapability;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterKbps;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterPktps;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterStats;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ActionType;
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.multipart.reply.multipart.reply.body.MultipartReplyDescCase;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyGroupFeaturesCase;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyMeterFeaturesCase;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.MultipartReplyTableFeaturesCase;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.desc._case.MultipartReplyDesc;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.group.features._case.MultipartReplyGroupFeatures;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.meter.features._case.MultipartReplyMeterFeatures;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table.features._case.MultipartReplyTableFeatures;
71 import org.slf4j.Logger;
72 import org.slf4j.LoggerFactory;
73
74 /**
75  * openflowplugin-impl
76  * org.opendaylight.openflowplugin.impl.device
77  *
78  * Class is a helper to prepare FlowCapableNode with whole internal future structure.
79  * Everything is realized by {@link ListenableFuture} objects.
80  *
81  * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
82  *
83  * Created: Mar 27, 2015
84  */
85 class PostHandshakeNodeProducer {
86
87     private static final Logger LOG = LoggerFactory.getLogger(PostHandshakeNodeProducer.class);
88
89     private final Map<Long, Future<?>> futures;
90     private final XidGenerator xidGenerator;
91     private final ConnectionContext connectionContext;
92     private SettableFuture<Node> deviceFuture;
93
94     public PostHandshakeNodeProducer (@Nonnull final ConnectionContext connectionContext,
95                                       @Nonnull final XidGenerator xidGenerator) {
96         this.xidGenerator = Preconditions.checkNotNull(xidGenerator);
97         this.connectionContext = Preconditions.checkNotNull(connectionContext);
98         futures = new ConcurrentHashMap<>();
99     }
100
101     public ListenableFuture<Node> prepareFlowCapabeNode() {
102         deviceFuture = SettableFuture.create();
103         final NodeBuilder nodeBuilder = new NodeBuilder();
104         nodeBuilder.setId(connectionContext.getNodeId());
105         nodeBuilder.setKey(new NodeKey(connectionContext.getNodeId()));
106         final Short version = connectionContext.getFeatures().getVersion();
107
108         final long nodeDescXid = xidGenerator.generate().getValue();
109         futures.put(nodeDescXid, queryDescription(connectionContext, nodeDescXid, nodeBuilder));
110
111         final long meterFutureXid = xidGenerator.generate().getValue();
112         futures.put(meterFutureXid, queryMeterFuture(connectionContext, meterFutureXid, nodeBuilder));
113
114         final long groupFutureXid = xidGenerator.generate().getValue();
115         futures.put(groupFutureXid, queryGroupFuture(connectionContext, groupFutureXid, nodeBuilder));
116
117         final long tableFutureXid = xidGenerator.generate().getValue();
118         futures.put(tableFutureXid, queryTableFuture(connectionContext, tableFutureXid, nodeBuilder));
119
120         connectionContext.getConnectionAdapter().multipartRequest(MultipartRequestInputFactory
121                 .makeMultipartRequestInput(nodeDescXid, version, MultipartType.OFPMPDESC));
122         connectionContext.getConnectionAdapter().multipartRequest(MultipartRequestInputFactory
123                 .makeMultipartRequestInput(meterFutureXid, version, MultipartType.OFPMPMETERFEATURES));
124         connectionContext.getConnectionAdapter().multipartRequest(MultipartRequestInputFactory
125                 .makeMultipartRequestInput(groupFutureXid, version, MultipartType.OFPMPGROUPFEATURES));
126         connectionContext.getConnectionAdapter().multipartRequest(MultipartRequestInputFactory
127                 .makeMultipartRequestInput(tableFutureXid, version, MultipartType.OFPMPTABLEFEATURES));
128
129         return deviceFuture;
130     }
131
132     private ListenableFuture<Collection<MultipartReply>> queryTableFuture(final ConnectionContext connectionContext,
133             final long tableFutureXid, final NodeBuilder nodeBuilder) {
134         final ListenableFuture<Collection<MultipartReply>> nodeTableFuture = connectionContext.registerMultipartMsg(tableFutureXid);
135         Futures.addCallback(nodeTableFuture, new FutureCallback<Collection<MultipartReply>>() {
136
137             @Override
138             public void onSuccess(final Collection<MultipartReply> result) {
139                 Preconditions.checkArgument(result != null && ( ! result.isEmpty()), "Node table future info result is null or empty!");
140                 final FlowCapableNode flowCapNode = nodeBuilder.getAugmentation(FlowCapableNode.class);
141                 final FlowCapableNodeBuilder flowCapAugBuilder = flowCapNode != null
142                         ? new FlowCapableNodeBuilder(flowCapNode) : new FlowCapableNodeBuilder();
143                 for (final MultipartReply reply : result) {
144                     final MultipartReplyTableFeaturesCase replyBody = (MultipartReplyTableFeaturesCase) reply.getMultipartReplyBody();
145                     final MultipartReplyTableFeatures tableFutures = replyBody.getMultipartReplyTableFeatures();
146                     // FIXME : add DataStore model in future commits in this chain
147                 }
148                 checkForFinalization(tableFutureXid, nodeBuilder);
149             }
150
151             @Override
152             public void onFailure(final Throwable t) {
153                 LOG.info("Failed to retrieve node table future info: {}", t.getMessage());
154                 checkForFinalization(tableFutureXid, nodeBuilder);
155             }
156         });
157
158         return nodeTableFuture;
159     }
160
161     private ListenableFuture<Collection<MultipartReply>> queryGroupFuture(final ConnectionContext connectionContext,
162             final long groupFutureXid, final NodeBuilder nodeBuilder) {
163         final ListenableFuture<Collection<MultipartReply>> nodeGroupFuture = connectionContext.registerMultipartMsg(groupFutureXid);
164         Futures.addCallback(nodeGroupFuture, new FutureCallback<Collection<MultipartReply>>() {
165
166             @Override
167             public void onSuccess(final Collection<MultipartReply> result) {
168                 Preconditions.checkArgument(result != null && ( ! result.isEmpty()), "Node group future info result is null or empty!");
169                 final NodeGroupFeaturesBuilder nodeGroupFeaturesBuilder = new NodeGroupFeaturesBuilder();
170                 final GroupFeaturesBuilder groupFeature = new GroupFeaturesBuilder();
171                 for (final MultipartReply reply : result) {
172                     final MultipartReplyGroupFeaturesCase replyBody = (MultipartReplyGroupFeaturesCase) reply.getMultipartReplyBody();
173                     final MultipartReplyGroupFeatures groupReplyFutures = replyBody.getMultipartReplyGroupFeatures();
174                     groupFeature.setMaxGroups(groupReplyFutures.getMaxGroups());
175                     final List<Class<? extends GroupType>> supportedGroups =  new ArrayList<>();
176                     if(groupReplyFutures.getTypes().isOFPGTALL()){
177                         supportedGroups.add(GroupAll.class);
178                     }
179                     if(groupReplyFutures.getTypes().isOFPGTSELECT()){
180                         supportedGroups.add(GroupSelect.class);
181                     }
182                     if(groupReplyFutures.getTypes().isOFPGTINDIRECT()){
183                         supportedGroups.add(GroupIndirect.class);
184                     }
185                     if(groupReplyFutures.getTypes().isOFPGTFF()){
186                         supportedGroups.add(GroupFf.class);
187                     }
188                     groupFeature.setGroupTypesSupported(supportedGroups);
189
190                     final List<Class<? extends GroupCapability>> gCapability = new ArrayList<>();
191                     if(groupReplyFutures.getCapabilities().isOFPGFCCHAINING()){
192                         gCapability.add(Chaining.class);
193                     }
194                     if(groupReplyFutures.getCapabilities().isOFPGFCCHAININGCHECKS()){
195                         gCapability.add(ChainingChecks.class);
196                     }
197                     if(groupReplyFutures.getCapabilities().isOFPGFCSELECTLIVENESS()){
198                         gCapability.add(SelectLiveness.class);
199                     }
200                     if(groupReplyFutures.getCapabilities().isOFPGFCSELECTWEIGHT()){
201                         gCapability.add(SelectWeight.class);
202                     }
203                     groupFeature.setGroupCapabilitiesSupported(gCapability);
204                     /* TODO :
205                      *  My recommendation would be, its good to have a respective model of
206                      * 'type bits', which will generate a class where all these flags will eventually
207                      * be stored as boolean. It will be convenient for application to check the
208                      * supported action, rather then doing bitmap operation.
209                      */
210                     final List<Long> supportActionByGroups = new ArrayList<>();
211                     for (final ActionType actionType : groupReplyFutures.getActionsBitmap()) {
212                         long supportActionBitmap = 0;
213                         supportActionBitmap |= actionType.isOFPATOUTPUT()?(1 << 0): 0;
214                         supportActionBitmap |= actionType.isOFPATCOPYTTLOUT()?(1 << 11): 0;
215                         supportActionBitmap |= actionType.isOFPATCOPYTTLIN()?(1 << 12): 0;
216                         supportActionBitmap |= actionType.isOFPATSETMPLSTTL()?(1 << 15): 0;
217                         supportActionBitmap |= actionType.isOFPATDECMPLSTTL()?(1 << 16): 0;
218                         supportActionBitmap |= actionType.isOFPATPUSHVLAN()?(1 << 17): 0;
219                         supportActionBitmap |= actionType.isOFPATPOPVLAN()?(1 << 18): 0;
220                         supportActionBitmap |= actionType.isOFPATPUSHMPLS()?(1 << 19): 0;
221                         supportActionBitmap |= actionType.isOFPATPOPMPLS()?(1 << 20): 0;
222                         supportActionBitmap |= actionType.isOFPATSETQUEUE()?(1 << 21): 0;
223                         supportActionBitmap |= actionType.isOFPATGROUP()?(1 << 22): 0;
224                         supportActionBitmap |= actionType.isOFPATSETNWTTL()?(1 << 23): 0;
225                         supportActionBitmap |= actionType.isOFPATDECNWTTL()?(1 << 24): 0;
226                         supportActionBitmap |= actionType.isOFPATSETFIELD()?(1 << 25): 0;
227                         supportActionBitmap |= actionType.isOFPATPUSHPBB()?(1 << 26): 0;
228                         supportActionBitmap |= actionType.isOFPATPOPPBB()?(1 << 27): 0;
229                         supportActionByGroups.add(Long.valueOf(supportActionBitmap));
230                     }
231                     groupFeature.setActions(supportActionByGroups);
232                 }
233                 nodeGroupFeaturesBuilder.setGroupFeatures(groupFeature.build());
234                 nodeBuilder.addAugmentation(NodeGroupFeatures.class, nodeGroupFeaturesBuilder.build());
235                 checkForFinalization(groupFutureXid, nodeBuilder);
236             }
237
238             @Override
239             public void onFailure(final Throwable t) {
240                 LOG.info("Failed to retrieve node group future info: {}", t.getMessage());
241                 checkForFinalization(groupFutureXid, nodeBuilder);
242             }
243         });
244
245         return nodeGroupFuture;
246     }
247
248     private ListenableFuture<Collection<MultipartReply>> queryMeterFuture(final ConnectionContext connectionContext,
249             final long meterFutureXid, final NodeBuilder nodeBuilder) {
250         final ListenableFuture<Collection<MultipartReply>> nodeMeterFuture = connectionContext.registerMultipartMsg(meterFutureXid);
251         Futures.addCallback(nodeMeterFuture, new FutureCallback<Collection<MultipartReply>>() {
252
253             @Override
254             public void onSuccess(final Collection<MultipartReply> result) {
255                 Preconditions.checkArgument(result != null && ( ! result.isEmpty()), "Node meter future info result is null or empty!");
256                 final NodeMeterFeaturesBuilder nodeMeterFeaturesBuilder = new NodeMeterFeaturesBuilder();
257                 final MeterFeaturesBuilder meterFeature = new MeterFeaturesBuilder();
258                 for (final MultipartReply reply : result) {
259                     final MultipartReplyMeterFeaturesCase replyBody = (MultipartReplyMeterFeaturesCase) reply.getMultipartReplyBody();
260                     final MultipartReplyMeterFeatures meterReplyFutures = replyBody.getMultipartReplyMeterFeatures();
261                     meterFeature.setMaxBands(meterReplyFutures.getMaxBands());
262                     meterFeature.setMaxColor(meterReplyFutures.getMaxColor());
263                     meterFeature.setMaxMeter(new Counter32(meterReplyFutures.getMaxMeter()));
264                     final List<Class<? extends MeterBand>> meterBandTypes = new ArrayList<>();
265                     if (meterReplyFutures.getBandTypes().isOFPMBTDROP()) {
266                         meterBandTypes.add(MeterBandDrop.class);
267                     }
268                     if (meterReplyFutures.getBandTypes().isOFPMBTDSCPREMARK()) {
269                         meterBandTypes.add(MeterBandDscpRemark.class);
270                     }
271                     meterFeature.setMeterBandSupported(Collections.unmodifiableList(meterBandTypes));
272
273                     final List<java.lang.Class<? extends MeterCapability>> mCapability = new ArrayList<>();
274                     if (meterReplyFutures.getCapabilities().isOFPMFBURST()) {
275                         mCapability.add(MeterBurst.class);
276                     }
277                     if(meterReplyFutures.getCapabilities().isOFPMFKBPS()){
278                         mCapability.add(MeterKbps.class);
279
280                     }
281                     if(meterReplyFutures.getCapabilities().isOFPMFPKTPS()){
282                         mCapability.add(MeterPktps.class);
283
284                     }
285                     if(meterReplyFutures.getCapabilities().isOFPMFSTATS()){
286                         mCapability.add(MeterStats.class);
287
288                     }
289                     meterFeature.setMeterCapabilitiesSupported(Collections.unmodifiableList(mCapability));
290                 }
291                 nodeMeterFeaturesBuilder.setMeterFeatures(meterFeature.build());
292                 nodeBuilder.addAugmentation(NodeMeterFeatures.class, nodeMeterFeaturesBuilder.build());
293                 checkForFinalization(meterFutureXid, nodeBuilder);
294             }
295
296             @Override
297             public void onFailure(final Throwable t) {
298                 LOG.info("Failed to retrieve node meter future info: {}", t.getMessage());
299                 checkForFinalization(meterFutureXid, nodeBuilder);
300             }
301         });
302
303         return nodeMeterFuture;
304     }
305
306     private ListenableFuture<Collection<MultipartReply>> queryDescription(final ConnectionContext connectionContext,
307             final long nodeDescXid, final NodeBuilder nodeBuilder) {
308         final ListenableFuture<Collection<MultipartReply>> nodeDesc = connectionContext.registerMultipartMsg(nodeDescXid);
309         final Short nrOfTables = connectionContext.getFeatures().getTables();
310         Futures.addCallback(nodeDesc, new FutureCallback<Collection<MultipartReply>>() {
311
312             @Override
313             public void onSuccess(final Collection<MultipartReply> result) {
314                 Preconditions.checkArgument(result != null && ( ! result.isEmpty()), "Node static info result is null or empty!");
315                 final FlowCapableNode flowCapNode = nodeBuilder.getAugmentation(FlowCapableNode.class);
316                 final FlowCapableNodeBuilder flowCapAugBuilder = flowCapNode != null
317                         ? new FlowCapableNodeBuilder(flowCapNode) : new FlowCapableNodeBuilder();
318                 final List<Table> tables = flowCapAugBuilder.getTable();
319                 for (int i = 0; i < nrOfTables.intValue(); i++) {
320                     final Short id = Short.valueOf(((short) i));
321                     tables.add(new TableBuilder().setId(id).setKey(new TableKey(id)).build());
322                 }
323                 flowCapAugBuilder.setTable(tables);
324                 for (final MultipartReply reply : result) {
325                     final MultipartReplyDescCase replyBody = (MultipartReplyDescCase) reply.getMultipartReplyBody();
326                     final MultipartReplyDesc description = replyBody.getMultipartReplyDesc();
327                     flowCapAugBuilder.setDescription(choiseValues(flowCapAugBuilder.getDescription(), description.getDpDesc()));
328                     flowCapAugBuilder.setHardware(choiseValues(flowCapAugBuilder.getHardware(), description.getHwDesc()));
329                     flowCapAugBuilder.setManufacturer(choiseValues(flowCapAugBuilder.getManufacturer(), description.getMfrDesc()));
330                     flowCapAugBuilder.setSoftware(choiseValues(flowCapAugBuilder.getSoftware(), description.getSwDesc()));
331                     flowCapAugBuilder.setSerialNumber(choiseValues(flowCapAugBuilder.getSerialNumber(), description.getSerialNum()));
332                 }
333                 nodeBuilder.addAugmentation(FlowCapableNode.class, flowCapAugBuilder.build());
334                 checkForFinalization(nodeDescXid, nodeBuilder);
335             }
336
337             @Override
338             public void onFailure(final Throwable t) {
339                 LOG.info("Failed to retrieve node static info: {}", t.getMessage());
340                 checkForFinalization(nodeDescXid, nodeBuilder);
341             }
342         });
343
344         return nodeDesc;
345     }
346
347     private void checkForFinalization(final long xid, final NodeBuilder nodeBuilder) {
348         futures.remove(xid);
349         if (futures.isEmpty()) {
350             deviceFuture.set(nodeBuilder.build());
351         }
352     }
353
354     private static <T> T choiseValues(final T actual, final T newValue) {
355         if (actual == null || newValue != null) {
356             return newValue;
357         } else {
358             return actual;
359         }
360     }
361
362 }