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