2 * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.openflowplugin.impl.protocol.deserialization.multipart;
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;
14 import io.netty.buffer.ByteBuf;
15 import java.util.ArrayList;
16 import java.util.List;
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;
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();
81 private DeserializerRegistry registry = null;
84 public MultipartReplyBody deserialize(final ByteBuf message) {
85 final MultipartReplyTableFeaturesBuilder builder = new MultipartReplyTableFeaturesBuilder();
86 final var items = BindingMap.<TableFeaturesKey, TableFeatures>orderedBuilder();
88 while (message.readableBytes() > 0) {
89 final int itemLength = message.readUnsignedShort();
90 final Uint8 tableId = readUint8(message);
92 message.skipBytes(PADDING_IN_MULTIPART_REPLY_TABLE_FEATURES);
94 items.add(new TableFeaturesBuilder()
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))
107 .setTableFeatures(items.build())
111 private static TableConfig readTableConfig(final ByteBuf message) {
112 final long input = message.readUnsignedInt();
113 final boolean deprecated = (input & 3) != 0;
115 return new TableConfig(deprecated);
118 private TableProperties readTableProperties(final ByteBuf message, final int length) {
119 final var items = BindingMap.<TableFeaturePropertiesKey, TableFeatureProperties>orderedBuilder();
120 int tableFeaturesLength = length;
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()
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))
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))
151 case OFPTFPTNEXTTABLES:
152 propBuilder.setTableFeaturePropType(new NextTableBuilder()
153 .setTables(new TablesBuilder()
154 .setTableIds(readNextTableIds(message, commonPropertyLength))
158 case OFPTFPTNEXTTABLESMISS:
159 propBuilder.setTableFeaturePropType(new NextTableMissBuilder()
160 .setTablesMiss(new TablesMissBuilder()
161 .setTableIds(readNextTableIds(message, commonPropertyLength))
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))
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))
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))
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))
200 propBuilder.setTableFeaturePropType(new MatchBuilder()
201 .setMatchSetfield(new MatchSetfieldBuilder()
202 .setSetFieldMatch(readMatchFields(message, commonPropertyLength))
206 case OFPTFPTWILDCARDS:
207 propBuilder.setTableFeaturePropType(new WildcardsBuilder()
208 .setWildcardSetfield(new WildcardSetfieldBuilder()
209 .setSetFieldMatch(readMatchFields(message, commonPropertyLength))
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))
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))
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))
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))
247 case OFPTFPTEXPERIMENTER:
248 case OFPTFPTEXPERIMENTERMISS:
249 final Uint32 expId = readUint32(message);
250 message.readerIndex(propStartIndex);
252 final OFDeserializer<TableFeatureProperties> propDeserializer = registry
253 .getDeserializer(ExperimenterDeserializerKeyFactory
254 .createMultipartReplyTFDeserializerKey(EncodeConstants.OF_VERSION_1_3, expId));
256 // TODO: Finish experimenter table features (currently using OFJava deserialization only to skip
258 propDeserializer.deserialize(message);
259 LOG.debug("Table feature property type {} is not handled yet.", propType);
266 if (paddingRemainder != 0) {
267 message.skipBytes(EncodeConstants.PADDING - paddingRemainder);
268 tableFeaturesLength -= EncodeConstants.PADDING - paddingRemainder;
271 items.add(propBuilder.build());
275 return new TablePropertiesBuilder()
276 .setTableFeatureProperties(items.build())
280 private static Map<SetFieldMatchKey, SetFieldMatch> readMatchFields(final ByteBuf message, final int length) {
281 final var matchFields = BindingMap.<SetFieldMatchKey, SetFieldMatch>orderedBuilder();
283 final int startIndex = message.readerIndex();
285 while (message.readerIndex() - startIndex < length) {
286 final var field = MATCH_FIELD_DESERIALIZER.deserialize(message);
287 if (field.isPresent()) {
288 matchFields.add(field.orElseThrow());
290 message.skipBytes(2 * Short.BYTES);
294 return matchFields.build();
297 private static List<Uint8> readNextTableIds(final ByteBuf message, final int length) {
298 final List<Uint8> tableIds = new ArrayList<>();
299 int nextTableLength = length;
301 while (nextTableLength > 0) {
302 tableIds.add(readUint8(message));
303 nextTableLength -= 1;
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();
314 while (message.readerIndex() - startIndex < length) {
316 instructions.add(new InstructionBuilder()
318 .setInstruction(InstructionUtil
319 .readInstructionHeader(EncodeConstants.OF_VERSION_1_3, message, registry))
323 } catch (ClassCastException | IllegalStateException e) {
324 // FIXME: what are we guarding here?
325 message.skipBytes(2 * Short.BYTES);
329 return instructions.build();
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();
337 while (message.readerIndex() - startIndex < length) {
339 actions.add(new ActionBuilder()
341 .setAction(ActionUtil.readActionHeader(EncodeConstants.OF_VERSION_1_3, message, registry,
342 ActionPath.FLOWS_STATISTICS_UPDATE_APPLY_ACTIONS))
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);
353 return actions.build();
357 public void injectDeserializerRegistry(final DeserializerRegistry deserializerRegistry) {
358 registry = deserializerRegistry;