Fixing OF Multipart messages
[openflowjava.git] / openflow-protocol-impl / src / main / java / org / opendaylight / openflowjava / protocol / impl / serialization / factories / MultipartRequestMessageFactory.java
1 /* Copyright (C)2013 Pantheon Technologies, s.r.o. All rights reserved. */\r
2 package org.opendaylight.openflowjava.protocol.impl.serialization.factories;\r
3 \r
4 import io.netty.buffer.ByteBuf;\r
5 \r
6 import java.util.HashMap;\r
7 import java.util.List;\r
8 import java.util.Map;\r
9 \r
10 import org.opendaylight.openflowjava.protocol.impl.serialization.OFSerializer;\r
11 import org.opendaylight.openflowjava.protocol.impl.util.ActionsSerializer;\r
12 import org.opendaylight.openflowjava.protocol.impl.util.ByteBufUtils;\r
13 import org.opendaylight.openflowjava.protocol.impl.util.InstructionsSerializer;\r
14 import org.opendaylight.openflowjava.protocol.impl.util.MatchSerializer;\r
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ActionRelatedTableFeatureProperty;\r
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ExperimenterRelatedTableFeatureProperty;\r
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.InstructionRelatedTableFeatureProperty;\r
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.NextTableRelatedTableFeatureProperty;\r
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.OxmRelatedTableFeatureProperty;\r
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.table.features.properties.container.table.feature.properties.NextTableIds;\r
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.actions.ActionsList;\r
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.instructions.Instructions;\r
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartRequestFlags;\r
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;\r
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.TableConfig;\r
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.TableFeaturesPropType;\r
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.oxm.fields.MatchEntries;\r
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartRequestMessage;\r
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.MultipartRequestBody;\r
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestAggregate;\r
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestDesc;\r
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestExperimenter;\r
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestFlow;\r
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestGroup;\r
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestMeter;\r
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestMeterConfig;\r
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestPortStats;\r
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestQueue;\r
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestTableFeatures;\r
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.table.features.TableFeatures;\r
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.table.features.properties.TableFeatureProperties;\r
42 \r
43 /**\r
44  * @author timotej.kubas\r
45  * @author michal.polkorab\r
46  */\r
47 public class MultipartRequestMessageFactory implements OFSerializer<MultipartRequestMessage> {\r
48     private static final byte MESSAGE_TYPE = 18;\r
49     private static final int MESSAGE_LENGTH = 16;\r
50     private static final byte PADDING_IN_MULTIPART_REQUEST_MESSAGE = 4;\r
51     private static final byte TABLE_FEAT_HEADER_LENGTH = 4;\r
52     private static MultipartRequestMessageFactory instance;\r
53 \r
54     private MultipartRequestMessageFactory() {\r
55         // singleton\r
56     }\r
57 \r
58     /**\r
59      * @return singleton factory\r
60      */\r
61     public static synchronized MultipartRequestMessageFactory getInstance() {\r
62         if (instance == null) {\r
63             instance = new MultipartRequestMessageFactory();\r
64         }\r
65         return instance;\r
66     }\r
67 \r
68     @Override\r
69     public void messageToBuffer(short version, ByteBuf out,\r
70             MultipartRequestMessage message) {\r
71         ByteBufUtils.writeOFHeader(instance, message, out);\r
72         out.writeShort(message.getType().getIntValue());\r
73         out.writeShort(createMultipartRequestFlagsBitmask(message.getFlags()));\r
74         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_MESSAGE, out);\r
75 \r
76         if (message.getMultipartRequestBody() instanceof MultipartRequestDesc ){\r
77             encodeDescBody(message.getMultipartRequestBody(), out);\r
78         } else if (message.getMultipartRequestBody() instanceof MultipartRequestFlow) {\r
79             encodeFlowBody(message.getMultipartRequestBody(), out);\r
80         } else if (message.getMultipartRequestBody() instanceof MultipartRequestAggregate) {\r
81             encodeAggregateBody(message.getMultipartRequestBody(), out);\r
82         } else if (message.getMultipartRequestBody() instanceof MultipartRequestPortStats) {\r
83             encodePortStatsBody(message.getMultipartRequestBody(), out);\r
84         } else if (message.getMultipartRequestBody() instanceof MultipartRequestQueue) {\r
85             encodeQueueBody(message.getMultipartRequestBody(), out);\r
86         } else if (message.getMultipartRequestBody() instanceof MultipartRequestGroup) {\r
87             encodeGroupStatsBody(message.getMultipartRequestBody(), out);\r
88         } else if (message.getMultipartRequestBody() instanceof MultipartRequestMeter) {\r
89             encodeMeterBody(message.getMultipartRequestBody(), out);\r
90         } else if (message.getMultipartRequestBody() instanceof MultipartRequestMeterConfig) {\r
91             encodeMeterConfigBody(message.getMultipartRequestBody(), out);\r
92         } else if (message.getMultipartRequestBody() instanceof MultipartRequestTableFeatures) {\r
93             encodeTableFeaturesBody(message.getMultipartRequestBody(), out);\r
94         } else if (message.getMultipartRequestBody() instanceof MultipartRequestExperimenter) {\r
95             encodeExperimenterBody(message.getMultipartRequestBody(), out);\r
96         }\r
97     }\r
98 \r
99     @Override\r
100     public int computeLength(MultipartRequestMessage message) {\r
101         return MESSAGE_LENGTH + computeBodyLength(message);\r
102     }\r
103     @Override\r
104     public byte getMessageType() {\r
105         return MESSAGE_TYPE;\r
106     }\r
107 \r
108     /**\r
109      *\r
110      * @param message\r
111      * @return length of MultipartRequestMessage\r
112      */\r
113     public int computeBodyLength(MultipartRequestMessage message) {\r
114         int length = 0;\r
115         MultipartType type = message.getType();\r
116         if (type.equals(MultipartType.OFPMPFLOW)) {\r
117             final byte FLOW_BODY_LENGTH = 32;\r
118             MultipartRequestFlow body = (MultipartRequestFlow) message.getMultipartRequestBody();\r
119             length += FLOW_BODY_LENGTH + MatchSerializer.computeMatchLength(body.getMatch());\r
120         } else if (type.equals(MultipartType.OFPMPAGGREGATE)) {\r
121             final byte AGGREGATE_BODY_LENGTH = 32;\r
122             MultipartRequestAggregate body = (MultipartRequestAggregate) message.getMultipartRequestBody();\r
123             length += AGGREGATE_BODY_LENGTH + MatchSerializer.computeMatchLength(body.getMatch());\r
124         } else if (type.equals(MultipartType.OFPMPPORTSTATS)) {\r
125             final byte PORT_STATS_BODY_LENGTH = 8;\r
126             length += PORT_STATS_BODY_LENGTH;\r
127         } else if (type.equals(MultipartType.OFPMPQUEUE)) {\r
128             final byte QUEUE_BODY_LENGTH = 8;\r
129             length += QUEUE_BODY_LENGTH;\r
130         } else if (type.equals(MultipartType.OFPMPGROUP)) {\r
131             final byte GROUP_BODY_LENGTH = 8;\r
132             length += GROUP_BODY_LENGTH;\r
133         } else if (type.equals(MultipartType.OFPMPMETER)) {\r
134             final byte METER_BODY_LENGTH = 8;\r
135             length += METER_BODY_LENGTH;\r
136         } else if (type.equals(MultipartType.OFPMPMETERCONFIG)) {\r
137             final byte METER_CONFIG_BODY_LENGTH = 8;\r
138             length += METER_CONFIG_BODY_LENGTH;\r
139         } else if (type.equals(MultipartType.OFPMPTABLEFEATURES)) {\r
140             MultipartRequestTableFeatures body = (MultipartRequestTableFeatures) message.getMultipartRequestBody();\r
141             length += computeTableFeaturesLength(body);\r
142         } else if (type.equals(MultipartType.OFPMPEXPERIMENTER)) {\r
143             final byte EXPERIMENTER_BODY_LENGTH = 8;\r
144             MultipartRequestExperimenter body = (MultipartRequestExperimenter) message.getMultipartRequestBody();\r
145             length += EXPERIMENTER_BODY_LENGTH;\r
146             if (body.getData() != null) {\r
147                 length += body.getData().length;\r
148             }\r
149         }\r
150         return length;\r
151     }\r
152 \r
153     private static int computeTableFeaturesLength(MultipartRequestTableFeatures body) {\r
154         final byte TABLE_FEATURES_LENGTH = 64;\r
155         final byte STRUCTURE_HEADER_LENGTH = 4;\r
156         int length = 0;\r
157         if (body != null) {\r
158             List<TableFeatures> tableFeatures = body.getTableFeatures();\r
159             for (TableFeatures feature : tableFeatures) {\r
160                 length += TABLE_FEATURES_LENGTH;\r
161                 List<TableFeatureProperties> featureProperties = feature.getTableFeatureProperties();\r
162                 if (featureProperties != null) {\r
163                     for (TableFeatureProperties featProp : featureProperties) {\r
164                         length += TABLE_FEAT_HEADER_LENGTH;\r
165                         if (featProp.getAugmentation(InstructionRelatedTableFeatureProperty.class) != null) {\r
166                             InstructionRelatedTableFeatureProperty property =\r
167                                     featProp.getAugmentation(InstructionRelatedTableFeatureProperty.class);\r
168                             length += property.getInstructions().size() * STRUCTURE_HEADER_LENGTH;\r
169                         } else if (featProp.getAugmentation(NextTableRelatedTableFeatureProperty.class) != null) {\r
170                             NextTableRelatedTableFeatureProperty property =\r
171                                     featProp.getAugmentation(NextTableRelatedTableFeatureProperty.class);\r
172                             length += property.getNextTableIds().size();\r
173                         } else if (featProp.getAugmentation(ActionRelatedTableFeatureProperty.class) != null) {\r
174                             ActionRelatedTableFeatureProperty property =\r
175                                     featProp.getAugmentation(ActionRelatedTableFeatureProperty.class);\r
176                             length += property.getActionsList().size() * STRUCTURE_HEADER_LENGTH;\r
177                         } else if (featProp.getAugmentation(OxmRelatedTableFeatureProperty.class) != null) {\r
178                             OxmRelatedTableFeatureProperty property =\r
179                                     featProp.getAugmentation(OxmRelatedTableFeatureProperty.class);\r
180                             length += property.getMatchEntries().size() * STRUCTURE_HEADER_LENGTH;\r
181                         } else if (featProp.getAugmentation(ExperimenterRelatedTableFeatureProperty.class) != null) {\r
182                             ExperimenterRelatedTableFeatureProperty property =\r
183                                     featProp.getAugmentation(ExperimenterRelatedTableFeatureProperty.class);\r
184                             length += 2 * (Integer.SIZE / Byte.SIZE);\r
185                             if (property.getData() != null) {\r
186                                 length += property.getData().length;\r
187                             }\r
188                         }\r
189                     }\r
190                 }\r
191             }\r
192         }\r
193         return length;\r
194     }\r
195 \r
196     private static int createMultipartRequestFlagsBitmask(MultipartRequestFlags flags) {\r
197         int multipartRequestFlagsBitmask = 0;\r
198         Map<Integer, Boolean> multipartRequestFlagsMap = new HashMap<>();\r
199         multipartRequestFlagsMap.put(0, flags.isOFPMPFREQMORE());\r
200 \r
201         multipartRequestFlagsBitmask = ByteBufUtils.fillBitMaskFromMap(multipartRequestFlagsMap);\r
202         return multipartRequestFlagsBitmask;\r
203     }\r
204 \r
205     private void encodeDescBody(MultipartRequestBody multipartRequestBody,\r
206             ByteBuf output) {\r
207         // The body of MultiPartRequestDesc is empty\r
208 \r
209     }\r
210 \r
211     private static void encodeFlowBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {\r
212         final byte PADDING_IN_MULTIPART_REQUEST_FLOW_BODY_01 = 3;\r
213         final byte PADDING_IN_MULTIPART_REQUEST_FLOW_BODY_02 = 4;\r
214         MultipartRequestFlow flow = (MultipartRequestFlow) multipartRequestBody;\r
215         output.writeByte(flow.getTableId().byteValue());\r
216         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_FLOW_BODY_01, output);\r
217         output.writeInt(flow.getOutPort().intValue());\r
218         output.writeInt(flow.getOutGroup().intValue());\r
219         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_FLOW_BODY_02, output);\r
220         output.writeLong(flow.getCookie().longValue());\r
221         output.writeLong(flow.getCookieMask().longValue());\r
222         MatchSerializer.encodeMatch(flow.getMatch(), output);\r
223     }\r
224 \r
225     private static void encodeAggregateBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {\r
226         final byte PADDING_IN_MULTIPART_REQUEST_AGREGGATE_BODY_01 = 3;\r
227         final byte PADDING_IN_MULTIPART_REQUEST_AGREGGATE_BODY_02 = 4;\r
228         MultipartRequestAggregate aggregate = (MultipartRequestAggregate) multipartRequestBody;\r
229         output.writeByte(aggregate.getTableId().byteValue());\r
230         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_AGREGGATE_BODY_01, output);\r
231         output.writeInt(aggregate.getOutPort().intValue());\r
232         output.writeInt(aggregate.getOutGroup().intValue());\r
233         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_AGREGGATE_BODY_02, output);\r
234         output.writeLong(aggregate.getCookie().longValue());\r
235         output.writeLong(aggregate.getCookieMask().longValue());\r
236         MatchSerializer.encodeMatch(aggregate.getMatch(), output);\r
237     }\r
238 \r
239     private static void encodePortStatsBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {\r
240         final byte PADDING_IN_MULTIPART_REQUEST_PORTSTATS_BODY = 4;\r
241         MultipartRequestPortStats portstats = (MultipartRequestPortStats) multipartRequestBody;\r
242         output.writeInt(portstats.getPortNo().intValue());\r
243         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_PORTSTATS_BODY, output);\r
244     }\r
245 \r
246     private static void encodeQueueBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {\r
247         MultipartRequestQueue queue = (MultipartRequestQueue) multipartRequestBody;\r
248         output.writeInt(queue.getPortNo().intValue());\r
249         output.writeInt(queue.getQueueId().intValue());\r
250     }\r
251 \r
252     private static void encodeGroupStatsBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {\r
253         final byte PADDING_IN_MULTIPART_REQUEST_GROUP_BODY = 4;\r
254         MultipartRequestGroup groupStats = (MultipartRequestGroup) multipartRequestBody;\r
255         output.writeInt(groupStats.getGroupId().intValue());\r
256         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_GROUP_BODY, output);\r
257     }\r
258 \r
259     private static void encodeMeterBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {\r
260         final byte PADDING_IN_MULTIPART_REQUEST_METER_BODY = 4;\r
261         MultipartRequestMeter meter = (MultipartRequestMeter) multipartRequestBody;\r
262         output.writeInt(meter.getMeterId().intValue());\r
263         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_METER_BODY, output);\r
264     }\r
265 \r
266     private static void encodeMeterConfigBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {\r
267         final byte PADDING_IN_MULTIPART_REQUEST_METER_CONFIG_BODY = 4;\r
268         MultipartRequestMeterConfig meterConfig = (MultipartRequestMeterConfig) multipartRequestBody;\r
269         output.writeInt(meterConfig.getMeterId().intValue());\r
270         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_METER_CONFIG_BODY, output);\r
271     }\r
272 \r
273     private static void encodeExperimenterBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {\r
274         MultipartRequestExperimenter experimenter = (MultipartRequestExperimenter) multipartRequestBody;\r
275         output.writeInt(experimenter.getExperimenter().intValue());\r
276         output.writeInt(experimenter.getExpType().intValue());\r
277         byte[] data = experimenter.getData();\r
278         if (data != null) {\r
279             output.writeBytes(data);\r
280         }\r
281     }\r
282 \r
283     private static void encodeTableFeaturesBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {\r
284         if (multipartRequestBody != null) {\r
285             MultipartRequestTableFeatures tableFeatures = (MultipartRequestTableFeatures) multipartRequestBody;\r
286             for (TableFeatures currTableFeature : tableFeatures.getTableFeatures()) {\r
287                 final byte PADDING_IN_MULTIPART_REQUEST_TABLE_FEATURES_BODY = 5;\r
288                 output.writeByte(currTableFeature.getTableId());\r
289                 ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_TABLE_FEATURES_BODY, output);\r
290                 output.writeBytes(currTableFeature.getName().getBytes());\r
291                 ByteBufUtils.padBuffer((32 - currTableFeature.getName().getBytes().length), output);\r
292                 output.writeLong(currTableFeature.getMetadataMatch().longValue());\r
293                 output.writeLong(currTableFeature.getMetadataWrite().longValue());\r
294                 output.writeInt(createTableConfigBitmask(currTableFeature.getConfig()));\r
295                 output.writeInt(currTableFeature.getMaxEntries().intValue());\r
296                 writeTableFeatureProperties(output, currTableFeature.getTableFeatureProperties());\r
297             }\r
298         }\r
299     }\r
300 \r
301     private static void writeTableFeatureProperties(ByteBuf output, List<TableFeatureProperties> props) {\r
302         if (props != null) {\r
303             for (TableFeatureProperties property : props) {\r
304                 TableFeaturesPropType type = property.getType();\r
305                 if (type.equals(TableFeaturesPropType.OFPTFPTINSTRUCTIONS)) {\r
306                     final byte INSTRUCTIONS_CODE = 0;\r
307                     writeInstructionRelatedTableProperty(output, property, INSTRUCTIONS_CODE);\r
308                 } else if (type.equals(TableFeaturesPropType.OFPTFPTINSTRUCTIONSMISS)) {\r
309                     final byte INSTRUCTIONS_MISS_CODE = 1;\r
310                     writeInstructionRelatedTableProperty(output, property, INSTRUCTIONS_MISS_CODE);\r
311                 } else if (type.equals(TableFeaturesPropType.OFPTFPTNEXTTABLES)) {\r
312                     final byte NEXT_TABLE_CODE = 2;\r
313                     writeNextTableRelatedTableProperty(output, property, NEXT_TABLE_CODE);\r
314                 } else if (type.equals(TableFeaturesPropType.OFPTFPTNEXTTABLESMISS)) {\r
315                     final byte NEXT_TABLE_MISS_CODE = 3;\r
316                     writeNextTableRelatedTableProperty(output, property, NEXT_TABLE_MISS_CODE);\r
317                 } else if (type.equals(TableFeaturesPropType.OFPTFPTWRITEACTIONS)) {\r
318                     final byte WRITE_ACTIONS_CODE = 4;\r
319                     writeActionsRelatedTableProperty(output, property, WRITE_ACTIONS_CODE);\r
320                 } else if (type.equals(TableFeaturesPropType.OFPTFPTWRITEACTIONSMISS)) {\r
321                     final byte WRITE_ACTIONS_MISS_CODE = 5;\r
322                     writeActionsRelatedTableProperty(output, property, WRITE_ACTIONS_MISS_CODE);\r
323                 } else if (type.equals(TableFeaturesPropType.OFPTFPTAPPLYACTIONS)) {\r
324                     final byte APPLY_ACTIONS_CODE = 6;\r
325                     writeActionsRelatedTableProperty(output, property, APPLY_ACTIONS_CODE);\r
326                 } else if (type.equals(TableFeaturesPropType.OFPTFPTAPPLYACTIONSMISS)) {\r
327                     final byte APPLY_ACTIONS_MISS_CODE = 7;\r
328                     writeActionsRelatedTableProperty(output, property, APPLY_ACTIONS_MISS_CODE);\r
329                 } else if (type.equals(TableFeaturesPropType.OFPTFPTMATCH)) {\r
330                     final byte MATCH_CODE = 8;\r
331                     writeOxmRelatedTableProperty(output, property, MATCH_CODE);\r
332                 } else if (type.equals(TableFeaturesPropType.OFPTFPTWILDCARDS)) {\r
333                     final byte WILDCARDS_CODE = 10;\r
334                     writeOxmRelatedTableProperty(output, property, WILDCARDS_CODE);\r
335                 } else if (type.equals(TableFeaturesPropType.OFPTFPTWRITESETFIELD)) {\r
336                     final byte WRITE_SETFIELD_CODE = 12;\r
337                     writeOxmRelatedTableProperty(output, property, WRITE_SETFIELD_CODE);\r
338                 } else if (type.equals(TableFeaturesPropType.OFPTFPTWRITESETFIELDMISS)) {\r
339                     final byte WRITE_SETFIELD_MISS_CODE = 13;\r
340                     writeOxmRelatedTableProperty(output, property, WRITE_SETFIELD_MISS_CODE);\r
341                 } else if (type.equals(TableFeaturesPropType.OFPTFPTAPPLYSETFIELD)) {\r
342                     final byte APPLY_SETFIELD_CODE = 14;\r
343                     writeOxmRelatedTableProperty(output, property, APPLY_SETFIELD_CODE);\r
344                 } else if (type.equals(TableFeaturesPropType.OFPTFPTAPPLYSETFIELDMISS)) {\r
345                     final byte APPLY_SETFIELD_MISS_CODE = 15;\r
346                     writeOxmRelatedTableProperty(output, property, APPLY_SETFIELD_MISS_CODE);\r
347                 } else if (type.equals(TableFeaturesPropType.OFPTFPTEXPERIMENTER)) {\r
348                     final int EXPERIMENTER_CODE = 65534; // 0xFFFE\r
349                     writeExperimenterRelatedTableProperty(output, property, EXPERIMENTER_CODE);\r
350                 } else if (type.equals(TableFeaturesPropType.OFPTFPTEXPERIMENTERMISS)) {\r
351                     final int EXPERIMENTER_MISS_CODE = 65535; // 0xFFFF\r
352                     writeExperimenterRelatedTableProperty(output, property, EXPERIMENTER_MISS_CODE);\r
353                 }\r
354             }\r
355         }\r
356     }\r
357 \r
358     private static void writeInstructionRelatedTableProperty(ByteBuf output,\r
359             TableFeatureProperties property, byte code) {\r
360         output.writeShort(code);\r
361         List<Instructions> instructions = property.\r
362                 getAugmentation(InstructionRelatedTableFeatureProperty.class).getInstructions();\r
363         int length = TABLE_FEAT_HEADER_LENGTH;\r
364         if (instructions != null) {\r
365         output.writeShort(InstructionsSerializer.computeInstructionsLength(instructions)\r
366                 + TABLE_FEAT_HEADER_LENGTH);\r
367         InstructionsSerializer.encodeInstructions(instructions, output);\r
368         } else {\r
369             output.writeShort(length);\r
370         }\r
371     }\r
372 \r
373     private static void writeNextTableRelatedTableProperty(ByteBuf output,\r
374             TableFeatureProperties property, byte code) {\r
375         output.writeShort(code);\r
376         List<NextTableIds> nextTableIds = property.\r
377                 getAugmentation(NextTableRelatedTableFeatureProperty.class).getNextTableIds();\r
378         int length = TABLE_FEAT_HEADER_LENGTH;\r
379         if (nextTableIds != null) {\r
380             output.writeShort(length + nextTableIds.size());\r
381             for (NextTableIds next : nextTableIds) {\r
382                 output.writeByte(next.getTableId());\r
383             }\r
384         } else {\r
385             output.writeShort(length);\r
386         }\r
387     }\r
388 \r
389     private static void writeActionsRelatedTableProperty(ByteBuf output,\r
390             TableFeatureProperties property, byte code) {\r
391         output.writeShort(code);\r
392         List<ActionsList> actions = property.\r
393                 getAugmentation(ActionRelatedTableFeatureProperty.class).getActionsList();\r
394         int length = TABLE_FEAT_HEADER_LENGTH;\r
395         if (actions != null) {\r
396         output.writeShort(ActionsSerializer.computeLengthOfActions(actions)\r
397                 + TABLE_FEAT_HEADER_LENGTH);\r
398         ActionsSerializer.encodeActions(actions, output);\r
399         } else {\r
400             output.writeShort(length);\r
401         }\r
402     }\r
403 \r
404     private static void writeOxmRelatedTableProperty(ByteBuf output,\r
405             TableFeatureProperties property, byte code) {\r
406         output.writeShort(code);\r
407         List<MatchEntries> entries = property.\r
408                 getAugmentation(OxmRelatedTableFeatureProperty.class).getMatchEntries();\r
409         int length = TABLE_FEAT_HEADER_LENGTH;\r
410         if (entries != null) {\r
411         output.writeShort(MatchSerializer.computeMatchEntriesLength(entries)\r
412                 + TABLE_FEAT_HEADER_LENGTH);\r
413         MatchSerializer.encodeMatchEntries(entries, output);\r
414         } else {\r
415             output.writeShort(length);\r
416         }\r
417     }\r
418 \r
419     private static void writeExperimenterRelatedTableProperty(ByteBuf output,\r
420             TableFeatureProperties property, int code) {\r
421         output.writeShort(code);\r
422         ExperimenterRelatedTableFeatureProperty exp = property.\r
423                 getAugmentation(ExperimenterRelatedTableFeatureProperty.class);\r
424         byte[] data = exp.getData();\r
425         int length = TABLE_FEAT_HEADER_LENGTH + 2 * (Integer.SIZE / Byte.SIZE);\r
426         if (data != null) {\r
427             output.writeShort(length + data.length);\r
428             output.writeInt(exp.getExperimenter().intValue());\r
429             output.writeInt(exp.getExpType().intValue());\r
430             output.writeBytes(data);\r
431         } else {\r
432             output.writeShort(length);\r
433             output.writeInt(exp.getExperimenter().intValue());\r
434             output.writeInt(exp.getExpType().intValue());\r
435         }\r
436     }\r
437 \r
438     private static int createTableConfigBitmask(TableConfig tableConfig) {\r
439         int tableConfigBitmask = 0;\r
440         Map<Integer, Boolean> tableConfigMap = new HashMap<>();\r
441         tableConfigMap.put(3, tableConfig.isOFPTCDEPRECATEDMASK());\r
442 \r
443         tableConfigBitmask = ByteBufUtils.fillBitMaskFromMap(tableConfigMap);\r
444         return tableConfigBitmask;\r
445     }\r
446 }\r