Bump upstreams
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / protocol / deserialization / multipart / MultipartReplyTableFeaturesDeserializer.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 package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
9
10 import static org.opendaylight.yangtools.yang.common.netty.ByteBufUtils.readUint32;
11 import static org.opendaylight.yangtools.yang.common.netty.ByteBufUtils.readUint64;
12 import static org.opendaylight.yangtools.yang.common.netty.ByteBufUtils.readUint8;
13
14 import io.netty.buffer.ByteBuf;
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.Map;
18 import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry;
19 import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistryInjector;
20 import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
21 import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
22 import org.opendaylight.openflowjava.util.ByteBufUtils;
23 import org.opendaylight.openflowjava.util.ExperimenterDeserializerKeyFactory;
24 import org.opendaylight.openflowplugin.extension.api.path.ActionPath;
25 import org.opendaylight.openflowplugin.impl.protocol.deserialization.util.ActionUtil;
26 import org.opendaylight.openflowplugin.impl.protocol.deserialization.util.InstructionUtil;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.multipart.types.rev170112.multipart.reply.MultipartReplyBody;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.TableFeaturesPropType;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableConfig;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.multipart.reply.multipart.reply.body.MultipartReplyTableFeaturesBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.set.field.match.SetFieldMatch;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.set.field.match.SetFieldMatchKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.ApplyActionsBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.ApplyActionsMissBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.ApplySetfieldBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.ApplySetfieldMissBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.InstructionsBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.InstructionsMissBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.MatchBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.NextTableBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.NextTableMissBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.WildcardsBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.WriteActionsBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.WriteActionsMissBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.WriteSetfieldBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.WriteSetfieldMissBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.match.MatchSetfieldBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.next.table.TablesBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.next.table.miss.TablesMissBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature.prop.type.wildcards.WildcardSetfieldBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeaturesKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.table.features.TableProperties;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.table.features.TablePropertiesBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.table.features.table.properties.TableFeatureProperties;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.table.features.table.properties.TableFeaturePropertiesBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.table.features.table.properties.TableFeaturePropertiesKey;
65 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
66 import org.opendaylight.yangtools.yang.common.Uint32;
67 import org.opendaylight.yangtools.yang.common.Uint8;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
70
71 public class MultipartReplyTableFeaturesDeserializer implements OFDeserializer<MultipartReplyBody>,
72         DeserializerRegistryInjector {
73     private static final Logger LOG = LoggerFactory.getLogger(MultipartReplyTableFeaturesDeserializer.class);
74     private static final byte PADDING_IN_MULTIPART_REPLY_TABLE_FEATURES = 5;
75     private static final byte MAX_TABLE_NAME_LENGTH = 32;
76     private static final byte MULTIPART_REPLY_TABLE_FEATURES_STRUCTURE_LENGTH = 64;
77     private static final byte COMMON_PROPERTY_LENGTH = 4;
78     private static final TableFeaturesMatchFieldDeserializer MATCH_FIELD_DESERIALIZER =
79             new TableFeaturesMatchFieldDeserializer();
80
81     private DeserializerRegistry registry = null;
82
83     @Override
84     public MultipartReplyBody deserialize(final ByteBuf message) {
85         final MultipartReplyTableFeaturesBuilder builder = new MultipartReplyTableFeaturesBuilder();
86         final var items = BindingMap.<TableFeaturesKey, TableFeatures>orderedBuilder();
87
88         while (message.readableBytes() > 0) {
89             final int itemLength = message.readUnsignedShort();
90             final Uint8 tableId = readUint8(message);
91
92             message.skipBytes(PADDING_IN_MULTIPART_REPLY_TABLE_FEATURES);
93
94             items.add(new TableFeaturesBuilder()
95                     .setTableId(tableId)
96                     .setName(ByteBufUtils.decodeNullTerminatedString(message, MAX_TABLE_NAME_LENGTH))
97                     .setMetadataMatch(readUint64(message))
98                     .setMetadataWrite(readUint64(message))
99                     .setConfig(readTableConfig(message))
100                     .setMaxEntries(readUint32(message))
101                     .setTableProperties(readTableProperties(message,
102                             itemLength - MULTIPART_REPLY_TABLE_FEATURES_STRUCTURE_LENGTH))
103                     .build());
104         }
105
106         return builder
107                 .setTableFeatures(items.build())
108                 .build();
109     }
110
111     private static TableConfig readTableConfig(final ByteBuf message) {
112         final long input = message.readUnsignedInt();
113         final boolean deprecated = (input & 3) != 0;
114
115         return new TableConfig(deprecated);
116     }
117
118     private TableProperties readTableProperties(final ByteBuf message, final int length) {
119         final var items = BindingMap.<TableFeaturePropertiesKey, TableFeatureProperties>orderedBuilder();
120         int tableFeaturesLength = length;
121         int order = 0;
122         while (tableFeaturesLength > 0) {
123             final int propStartIndex = message.readerIndex();
124             final TableFeaturesPropType propType = TableFeaturesPropType.forValue(message.readUnsignedShort());
125             int propertyLength = message.readUnsignedShort();
126             final int paddingRemainder = propertyLength % EncodeConstants.PADDING;
127             tableFeaturesLength -= propertyLength;
128             final int commonPropertyLength = propertyLength - COMMON_PROPERTY_LENGTH;
129             final TableFeaturePropertiesBuilder propBuilder = new TableFeaturePropertiesBuilder()
130                 .setOrder(order++);
131
132             switch (propType) {
133                 case OFPTFPTINSTRUCTIONS:
134                     propBuilder.setTableFeaturePropType(new InstructionsBuilder()
135                             .setInstructions(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types
136                                 .rev131026.table.feature.prop.type.table.feature.prop.type.instructions
137                                 .InstructionsBuilder()
138                                 .setInstruction(readInstructions(message, commonPropertyLength))
139                                 .build())
140                             .build());
141                     break;
142                 case OFPTFPTINSTRUCTIONSMISS:
143                     propBuilder.setTableFeaturePropType(new InstructionsMissBuilder()
144                             .setInstructionsMiss(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types
145                                 .rev131026.table.feature.prop.type.table.feature.prop.type.instructions.miss
146                                 .InstructionsMissBuilder()
147                                 .setInstruction(readInstructions(message, commonPropertyLength))
148                                 .build())
149                             .build());
150                     break;
151                 case OFPTFPTNEXTTABLES:
152                     propBuilder.setTableFeaturePropType(new NextTableBuilder()
153                             .setTables(new TablesBuilder()
154                                 .setTableIds(readNextTableIds(message, commonPropertyLength))
155                                 .build())
156                             .build());
157                     break;
158                 case OFPTFPTNEXTTABLESMISS:
159                     propBuilder.setTableFeaturePropType(new NextTableMissBuilder()
160                             .setTablesMiss(new TablesMissBuilder()
161                                 .setTableIds(readNextTableIds(message, commonPropertyLength))
162                                 .build())
163                             .build());
164                     break;
165                 case OFPTFPTWRITEACTIONS:
166                     propBuilder.setTableFeaturePropType(new WriteActionsBuilder()
167                             .setWriteActions(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026
168                                 .table.feature.prop.type.table.feature.prop.type.write.actions.WriteActionsBuilder()
169                                 .setAction(readActions(message, commonPropertyLength))
170                                 .build())
171                             .build());
172                     break;
173                 case OFPTFPTWRITEACTIONSMISS:
174                     propBuilder.setTableFeaturePropType(new WriteActionsMissBuilder()
175                             .setWriteActionsMiss(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types
176                                 .rev131026.table.feature.prop.type.table.feature.prop.type.write.actions.miss
177                                 .WriteActionsMissBuilder()
178                                 .setAction(readActions(message, commonPropertyLength))
179                                 .build())
180                             .build());
181                     break;
182                 case OFPTFPTAPPLYACTIONS:
183                     propBuilder.setTableFeaturePropType(new ApplyActionsBuilder()
184                             .setApplyActions(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026
185                                 .table.feature.prop.type.table.feature.prop.type.apply.actions.ApplyActionsBuilder()
186                                 .setAction(readActions(message, commonPropertyLength))
187                                 .build())
188                             .build());
189                     break;
190                 case OFPTFPTAPPLYACTIONSMISS:
191                     propBuilder.setTableFeaturePropType(new ApplyActionsMissBuilder()
192                             .setApplyActionsMiss(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types
193                                 .rev131026.table.feature.prop.type.table.feature.prop.type.apply.actions.miss
194                                 .ApplyActionsMissBuilder()
195                                 .setAction(readActions(message, commonPropertyLength))
196                                 .build())
197                             .build());
198                     break;
199                 case OFPTFPTMATCH:
200                     propBuilder.setTableFeaturePropType(new MatchBuilder()
201                             .setMatchSetfield(new MatchSetfieldBuilder()
202                                 .setSetFieldMatch(readMatchFields(message, commonPropertyLength))
203                                 .build())
204                             .build());
205                     break;
206                 case OFPTFPTWILDCARDS:
207                     propBuilder.setTableFeaturePropType(new WildcardsBuilder()
208                             .setWildcardSetfield(new WildcardSetfieldBuilder()
209                                 .setSetFieldMatch(readMatchFields(message, commonPropertyLength))
210                                 .build())
211                             .build());
212                     break;
213                 case OFPTFPTWRITESETFIELD:
214                     propBuilder.setTableFeaturePropType(new WriteSetfieldBuilder()
215                             .setWriteSetfield(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026
216                                 .table.feature.prop.type.table.feature.prop.type.write.setfield.WriteSetfieldBuilder()
217                                 .setSetFieldMatch(readMatchFields(message, commonPropertyLength))
218                                 .build())
219                             .build());
220                     break;
221                 case OFPTFPTWRITESETFIELDMISS:
222                     propBuilder.setTableFeaturePropType(new WriteSetfieldMissBuilder()
223                             .setWriteSetfieldMiss(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types
224                                 .rev131026.table.feature.prop.type.table.feature.prop.type.write.setfield.miss
225                                 .WriteSetfieldMissBuilder()
226                                 .setSetFieldMatch(readMatchFields(message, commonPropertyLength))
227                                 .build())
228                             .build());
229                     break;
230                 case OFPTFPTAPPLYSETFIELD:
231                     propBuilder.setTableFeaturePropType(new ApplySetfieldBuilder()
232                             .setApplySetfield(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026
233                                 .table.feature.prop.type.table.feature.prop.type.apply.setfield.ApplySetfieldBuilder()
234                                 .setSetFieldMatch(readMatchFields(message, commonPropertyLength))
235                                 .build())
236                             .build());
237                     break;
238                 case OFPTFPTAPPLYSETFIELDMISS:
239                     propBuilder.setTableFeaturePropType(new ApplySetfieldMissBuilder()
240                             .setApplySetfieldMiss(new org.opendaylight.yang.gen.v1.urn.opendaylight.table.types
241                                 .rev131026.table.feature.prop.type.table.feature.prop.type.apply.setfield.miss
242                                 .ApplySetfieldMissBuilder()
243                                 .setSetFieldMatch(readMatchFields(message, commonPropertyLength))
244                                 .build())
245                             .build());
246                     break;
247                 case OFPTFPTEXPERIMENTER:
248                 case OFPTFPTEXPERIMENTERMISS:
249                     final Uint32 expId = readUint32(message);
250                     message.readerIndex(propStartIndex);
251
252                     final OFDeserializer<TableFeatureProperties> propDeserializer = registry
253                         .getDeserializer(ExperimenterDeserializerKeyFactory
254                                 .createMultipartReplyTFDeserializerKey(EncodeConstants.OF_VERSION_1_3, expId));
255
256                     // TODO: Finish experimenter table features (currently using OFJava deserialization only to skip
257                     // bytes)
258                     propDeserializer.deserialize(message);
259                     LOG.debug("Table feature property type {} is not handled yet.", propType);
260                     break;
261                 default:
262                     // no operation
263             }
264
265
266             if (paddingRemainder != 0) {
267                 message.skipBytes(EncodeConstants.PADDING - paddingRemainder);
268                 tableFeaturesLength -= EncodeConstants.PADDING - paddingRemainder;
269             }
270
271             items.add(propBuilder.build());
272         }
273
274
275         return new TablePropertiesBuilder()
276             .setTableFeatureProperties(items.build())
277             .build();
278     }
279
280     private static Map<SetFieldMatchKey, SetFieldMatch> readMatchFields(final ByteBuf message, final int length) {
281         final var matchFields = BindingMap.<SetFieldMatchKey, SetFieldMatch>orderedBuilder();
282
283         final int startIndex = message.readerIndex();
284
285         while (message.readerIndex() - startIndex < length) {
286             final var field = MATCH_FIELD_DESERIALIZER.deserialize(message);
287             if (field.isPresent()) {
288                 matchFields.add(field.orElseThrow());
289             } else {
290                 message.skipBytes(2 * Short.BYTES);
291             }
292         }
293
294         return matchFields.build();
295     }
296
297     private static List<Uint8> readNextTableIds(final ByteBuf message, final int length) {
298         final List<Uint8> tableIds = new ArrayList<>();
299         int nextTableLength = length;
300
301         while (nextTableLength > 0) {
302             tableIds.add(readUint8(message));
303             nextTableLength -= 1;
304         }
305
306         return tableIds;
307     }
308
309     private Map<InstructionKey, Instruction> readInstructions(final ByteBuf message, final int length) {
310         final var instructions = BindingMap.<InstructionKey, Instruction>orderedBuilder();
311         final int startIndex = message.readerIndex();
312         int offset = 0;
313
314         while (message.readerIndex() - startIndex < length) {
315             try {
316                 instructions.add(new InstructionBuilder()
317                         .setOrder(offset)
318                         .setInstruction(InstructionUtil
319                                 .readInstructionHeader(EncodeConstants.OF_VERSION_1_3, message, registry))
320                         .build());
321
322                 offset++;
323             } catch (ClassCastException | IllegalStateException e) {
324                 // FIXME: what are we guarding here?
325                 message.skipBytes(2 * Short.BYTES);
326             }
327         }
328
329         return instructions.build();
330     }
331
332     private Map<ActionKey, Action> readActions(final ByteBuf message, final int length) {
333         final var actions = BindingMap.<ActionKey, Action>orderedBuilder();
334         final int startIndex = message.readerIndex();
335         int offset = 0;
336
337         while (message.readerIndex() - startIndex < length) {
338             try {
339                 actions.add(new ActionBuilder()
340                         .setOrder(offset)
341                         .setAction(ActionUtil.readActionHeader(EncodeConstants.OF_VERSION_1_3, message, registry,
342                                 ActionPath.FLOWS_STATISTICS_UPDATE_APPLY_ACTIONS))
343                         .build());
344
345                 offset++;
346             } catch (ClassCastException | IllegalStateException e) {
347                 LOG.debug("Failed to build action", e);
348                 // FIXME: what are we guarding here?
349                 message.skipBytes(2 * Short.BYTES);
350             }
351         }
352
353         return actions.build();
354     }
355
356     @Override
357     public void injectDeserializerRegistry(final DeserializerRegistry deserializerRegistry) {
358         registry = deserializerRegistry;
359     }
360
361 }