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