TableFeatures fix (partial)
[openflowjava.git] / openflow-protocol-impl / src / main / java / org / opendaylight / openflowjava / protocol / impl / serialization / factories / MultipartRequestInputFactory.java
1 /*
2  * Copyright (c) 2013 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.openflowjava.protocol.impl.serialization.factories;
10
11 import io.netty.buffer.ByteBuf;
12
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16
17 import org.opendaylight.openflowjava.protocol.impl.serialization.OFSerializer;
18 import org.opendaylight.openflowjava.protocol.impl.util.ActionsSerializer;
19 import org.opendaylight.openflowjava.protocol.impl.util.ByteBufUtils;
20 import org.opendaylight.openflowjava.protocol.impl.util.EncodeConstants;
21 import org.opendaylight.openflowjava.protocol.impl.util.InstructionsSerializer;
22 import org.opendaylight.openflowjava.protocol.impl.util.MatchSerializer;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ActionRelatedTableFeatureProperty;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ExperimenterRelatedTableFeatureProperty;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.InstructionRelatedTableFeatureProperty;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.NextTableRelatedTableFeatureProperty;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.OxmRelatedTableFeatureProperty;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.table.features.properties.container.table.feature.properties.NextTableIds;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.actions.ActionsList;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.instructions.Instructions;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartRequestFlags;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartType;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.TableConfig;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.TableFeaturesPropType;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.oxm.fields.MatchEntries;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartRequestInput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.MultipartRequestBody;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestAggregateCase;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestDescCase;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestExperimenterCase;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestFlowCase;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestGroupCase;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestGroupDescCase;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestGroupFeaturesCase;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestMeterCase;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestMeterConfigCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestMeterFeaturesCase;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestPortDescCase;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestPortStatsCase;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestQueueCase;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestTableCase;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestTableFeaturesCase;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.aggregate._case.MultipartRequestAggregate;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.experimenter._case.MultipartRequestExperimenter;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.flow._case.MultipartRequestFlow;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.group._case.MultipartRequestGroup;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.meter._case.MultipartRequestMeter;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.meter.config._case.MultipartRequestMeterConfig;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.port.stats._case.MultipartRequestPortStats;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.queue._case.MultipartRequestQueue;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.table.features._case.MultipartRequestTableFeatures;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.multipart.request.table.features._case.multipart.request.table.features.TableFeatures;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.table.features.properties.TableFeatureProperties;
64
65 /**
66  * Translates MultipartRequest messages
67  * @author timotej.kubas
68  * @author michal.polkorab
69  */
70 public class MultipartRequestInputFactory implements OFSerializer<MultipartRequestInput> {
71     private static final byte MESSAGE_TYPE = 18;
72     private static final int MESSAGE_LENGTH = 16;
73     private static final byte PADDING_IN_MULTIPART_REQUEST_MESSAGE = 4;
74     private static final byte TABLE_FEAT_HEADER_LENGTH = 4;
75     private static MultipartRequestInputFactory instance;
76     private static final byte INSTRUCTIONS_CODE = 0;
77     private static final byte INSTRUCTIONS_MISS_CODE = 1;
78     private static final byte NEXT_TABLE_CODE = 2;
79     private static final byte NEXT_TABLE_MISS_CODE = 3;
80     private static final byte WRITE_ACTIONS_CODE = 4;
81     private static final byte WRITE_ACTIONS_MISS_CODE = 5;
82     private static final byte APPLY_ACTIONS_CODE = 6;
83     private static final byte APPLY_ACTIONS_MISS_CODE = 7;
84     private static final byte MATCH_CODE = 8;
85     private static final byte WILDCARDS_CODE = 10;
86     private static final byte WRITE_SETFIELD_CODE = 12;
87     private static final byte WRITE_SETFIELD_MISS_CODE = 13;
88     private static final byte APPLY_SETFIELD_CODE = 14;
89     private static final byte APPLY_SETFIELD_MISS_CODE = 15;
90     private static final int EXPERIMENTER_CODE = 65534; // 0xFFFE
91     private static final int EXPERIMENTER_MISS_CODE = 65535; // 0xFFFF
92     private static final byte FLOW_BODY_LENGTH = 32;
93     private static final byte AGGREGATE_BODY_LENGTH = 32;
94     private static final byte PORT_STATS_BODY_LENGTH = 8;
95     private static final byte QUEUE_BODY_LENGTH = 8;
96     private static final byte GROUP_BODY_LENGTH = 8;
97     private static final byte METER_BODY_LENGTH = 8;
98     private static final byte METER_CONFIG_BODY_LENGTH = 8;
99     private static final byte EXPERIMENTER_BODY_LENGTH = 8;
100     private static final byte TABLE_FEATURES_LENGTH = 64;
101     private static final byte STRUCTURE_HEADER_LENGTH = 4;
102     private static final byte PADDING_IN_MULTIPART_REQUEST_FLOW_BODY_01 = 3;
103     private static final byte PADDING_IN_MULTIPART_REQUEST_FLOW_BODY_02 = 4;
104     private static final byte PADDING_IN_MULTIPART_REQUEST_AGREGGATE_BODY_01 = 3;
105     private static final byte PADDING_IN_MULTIPART_REQUEST_AGREGGATE_BODY_02 = 4;
106     private static final byte PADDING_IN_MULTIPART_REQUEST_PORTSTATS_BODY = 4;
107     private static final byte PADDING_IN_MULTIPART_REQUEST_GROUP_BODY = 4;
108     private static final byte PADDING_IN_MULTIPART_REQUEST_METER_BODY = 4;
109     private static final byte PADDING_IN_MULTIPART_REQUEST_METER_CONFIG_BODY = 4;
110     private static final byte PADDING_IN_MULTIPART_REQUEST_TABLE_FEATURES_BODY = 5;
111     
112
113
114     private MultipartRequestInputFactory() {
115         // singleton
116     }
117
118     /**
119      * @return singleton factory
120      */
121     public static synchronized MultipartRequestInputFactory getInstance() {
122         if (instance == null) {
123             instance = new MultipartRequestInputFactory();
124         }
125         return instance;
126     }
127
128     @Override
129     public void messageToBuffer(short version, ByteBuf out,
130             MultipartRequestInput message) {
131         ByteBufUtils.writeOFHeader(instance, message, out);
132         out.writeShort(message.getType().getIntValue());
133         out.writeShort(createMultipartRequestFlagsBitmask(message.getFlags()));
134         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_MESSAGE, out);
135
136         if (message.getMultipartRequestBody() instanceof MultipartRequestDescCase){
137             encodeDescBody(message.getMultipartRequestBody(), out);
138         } else if (message.getMultipartRequestBody() instanceof MultipartRequestFlowCase) {
139             encodeFlowBody(message.getMultipartRequestBody(), out);
140         } else if (message.getMultipartRequestBody() instanceof MultipartRequestAggregateCase) {
141             encodeAggregateBody(message.getMultipartRequestBody(), out);
142         } else if (message.getMultipartRequestBody() instanceof MultipartRequestTableCase) {
143             encodeTableBody(message.getMultipartRequestBody(), out);
144         } else if (message.getMultipartRequestBody() instanceof MultipartRequestPortStatsCase) {
145             encodePortStatsBody(message.getMultipartRequestBody(), out);
146         } else if (message.getMultipartRequestBody() instanceof MultipartRequestQueueCase) {
147             encodeQueueBody(message.getMultipartRequestBody(), out);
148         } else if (message.getMultipartRequestBody() instanceof MultipartRequestGroupCase) {
149             encodeGroupStatsBody(message.getMultipartRequestBody(), out);
150         } else if (message.getMultipartRequestBody() instanceof MultipartRequestGroupDescCase) {
151             encodeGroupDescBody(message.getMultipartRequestBody(), out);
152         } else if (message.getMultipartRequestBody() instanceof MultipartRequestGroupFeaturesCase) {
153             encodeGroupFeaturesBody(message.getMultipartRequestBody(), out);
154         } else if (message.getMultipartRequestBody() instanceof MultipartRequestMeterCase) {
155             encodeMeterBody(message.getMultipartRequestBody(), out);
156         } else if (message.getMultipartRequestBody() instanceof MultipartRequestMeterConfigCase) {
157             encodeMeterConfigBody(message.getMultipartRequestBody(), out);
158         } else if (message.getMultipartRequestBody() instanceof MultipartRequestMeterFeaturesCase) {
159             encodeMeterFeaturesBody(message.getMultipartRequestBody(), out);
160         } else if (message.getMultipartRequestBody() instanceof MultipartRequestTableFeaturesCase) {
161             encodeTableFeaturesBody(message.getMultipartRequestBody(), out);
162         } else if (message.getMultipartRequestBody() instanceof MultipartRequestPortDescCase) {
163             encodePortDescBody(message.getMultipartRequestBody(), out);
164         } else if (message.getMultipartRequestBody() instanceof MultipartRequestExperimenterCase) {
165             encodeExperimenterBody(message.getMultipartRequestBody(), out);
166         }
167     }
168
169     @Override
170     public int computeLength(MultipartRequestInput message) {
171         return MESSAGE_LENGTH + computeBodyLength(message);
172     }
173     @Override
174     public byte getMessageType() {
175         return MESSAGE_TYPE;
176     }
177
178     /**
179      *
180      * @param message
181      * @return length of MultipartRequestMessage
182      */
183     public int computeBodyLength(MultipartRequestInput message) {
184         int length = 0;
185         MultipartType type = message.getType();
186         if (type.equals(MultipartType.OFPMPFLOW)) {
187             MultipartRequestFlowCase bodyCase = (MultipartRequestFlowCase) message.getMultipartRequestBody();
188             MultipartRequestFlow body = bodyCase.getMultipartRequestFlow();
189             length += FLOW_BODY_LENGTH + MatchSerializer.computeMatchLength(body.getMatch());
190         } else if (type.equals(MultipartType.OFPMPAGGREGATE)) {
191             MultipartRequestAggregateCase bodyCase = (MultipartRequestAggregateCase) message.getMultipartRequestBody();
192             MultipartRequestAggregate body = bodyCase.getMultipartRequestAggregate();
193             length += AGGREGATE_BODY_LENGTH + MatchSerializer.computeMatchLength(body.getMatch());
194         } else if (type.equals(MultipartType.OFPMPPORTSTATS)) {
195             length += PORT_STATS_BODY_LENGTH;
196         } else if (type.equals(MultipartType.OFPMPQUEUE)) {
197             length += QUEUE_BODY_LENGTH;
198         } else if (type.equals(MultipartType.OFPMPGROUP)) {
199             length += GROUP_BODY_LENGTH;
200         } else if (type.equals(MultipartType.OFPMPMETER)) {
201             length += METER_BODY_LENGTH;
202         } else if (type.equals(MultipartType.OFPMPMETERCONFIG)) {
203             length += METER_CONFIG_BODY_LENGTH;
204         } else if (type.equals(MultipartType.OFPMPTABLEFEATURES)) {
205             MultipartRequestTableFeaturesCase bodyCase = (MultipartRequestTableFeaturesCase) message.getMultipartRequestBody();
206             MultipartRequestTableFeatures body = bodyCase.getMultipartRequestTableFeatures();
207             length += computeTableFeaturesLength(body);
208         } else if (type.equals(MultipartType.OFPMPEXPERIMENTER)) {
209             MultipartRequestExperimenterCase bodyCase = (MultipartRequestExperimenterCase) message.getMultipartRequestBody();
210             MultipartRequestExperimenter body = bodyCase.getMultipartRequestExperimenter();
211             length += EXPERIMENTER_BODY_LENGTH;
212             if (body.getData() != null) {
213                 length += body.getData().length;
214             }
215         }
216         return length;
217     }
218
219     private static int computeTableFeaturesLength(MultipartRequestTableFeatures body) {
220         int length = 0;
221         if (body != null && body.getTableFeatures() != null) {
222             List<TableFeatures> tableFeatures = body.getTableFeatures();
223             for (TableFeatures feature : tableFeatures) {
224                 length += computeSingleTableFeatureLength(feature);
225             }
226         }
227         return length;
228     }
229     
230     private static int computeSingleTableFeatureLength(TableFeatures feature) {
231         return TABLE_FEATURES_LENGTH + computeTableFeatPropsLength(feature);
232     }
233
234     private static int computeTableFeatPropsLength(TableFeatures feature) {
235         int length = 0;
236         List<TableFeatureProperties> featureProperties = feature.getTableFeatureProperties();
237         if (featureProperties != null) {
238             for (TableFeatureProperties featProp : featureProperties) {
239                 length += TABLE_FEAT_HEADER_LENGTH;
240                 if (featProp.getAugmentation(InstructionRelatedTableFeatureProperty.class) != null) {
241                     InstructionRelatedTableFeatureProperty property =
242                             featProp.getAugmentation(InstructionRelatedTableFeatureProperty.class);
243                     length += property.getInstructions().size() * STRUCTURE_HEADER_LENGTH;
244                     length += paddingNeeded(length);
245                 } else if (featProp.getAugmentation(NextTableRelatedTableFeatureProperty.class) != null) {
246                     NextTableRelatedTableFeatureProperty property =
247                             featProp.getAugmentation(NextTableRelatedTableFeatureProperty.class);
248                     length += property.getNextTableIds().size();
249                     length += paddingNeeded(length);
250                 } else if (featProp.getAugmentation(ActionRelatedTableFeatureProperty.class) != null) {
251                     ActionRelatedTableFeatureProperty property =
252                             featProp.getAugmentation(ActionRelatedTableFeatureProperty.class);
253                     length += property.getActionsList().size() * STRUCTURE_HEADER_LENGTH;
254                     length += paddingNeeded(length);
255                 } else if (featProp.getAugmentation(OxmRelatedTableFeatureProperty.class) != null) {
256                     OxmRelatedTableFeatureProperty property =
257                             featProp.getAugmentation(OxmRelatedTableFeatureProperty.class);
258                     length += property.getMatchEntries().size() * STRUCTURE_HEADER_LENGTH;
259                     length += paddingNeeded(length);
260                 } else if (featProp.getAugmentation(ExperimenterRelatedTableFeatureProperty.class) != null) {
261                     ExperimenterRelatedTableFeatureProperty property =
262                             featProp.getAugmentation(ExperimenterRelatedTableFeatureProperty.class);
263                     length += 2 * (EncodeConstants.SIZE_OF_INT_IN_BYTES);
264                     if (property.getData() != null) {
265                         length += property.getData().length;
266                     }
267                     length += paddingNeeded(length);
268                 }
269             }
270         }
271         return length;
272     }
273     
274     
275
276     private static int createMultipartRequestFlagsBitmask(MultipartRequestFlags flags) {
277         int multipartRequestFlagsBitmask = 0;
278         Map<Integer, Boolean> multipartRequestFlagsMap = new HashMap<>();
279         multipartRequestFlagsMap.put(0, flags.isOFPMPFREQMORE());
280
281         multipartRequestFlagsBitmask = ByteBufUtils.fillBitMaskFromMap(multipartRequestFlagsMap);
282         return multipartRequestFlagsBitmask;
283     }
284
285     /**
286      * @param multipartRequestBody
287      * @param output
288      */
289     private void encodeDescBody(MultipartRequestBody multipartRequestBody,
290             ByteBuf output) {
291         // The body of MultiPartRequestDesc is empty
292     }
293
294     /**
295      * @param multipartRequestBody
296      * @param out
297      */
298     private void encodeTableBody(MultipartRequestBody multipartRequestBody,
299             ByteBuf out) {
300      // The body of MultiPartTable is empty
301     }
302
303     /**
304      * @param multipartRequestBody
305      * @param out
306      */
307     private void encodeGroupDescBody(MultipartRequestBody multipartRequestBody,
308             ByteBuf out) {
309      // The body of MultiPartRequestGroupDesc is empty
310     }
311
312     /**
313      * @param multipartRequestBody
314      * @param out
315      */
316     private void encodeGroupFeaturesBody(
317             MultipartRequestBody multipartRequestBody, ByteBuf out) {
318      // The body of MultiPartRequestGroupFeatures is empty
319     }
320
321     /**
322      * @param multipartRequestBody
323      * @param out
324      */
325     private void encodeMeterFeaturesBody(
326             MultipartRequestBody multipartRequestBody, ByteBuf out) {
327      // The body of MultiPartMeterFeatures is empty
328     }
329
330     /**
331      * @param multipartRequestBody
332      * @param out
333      */
334     private void encodePortDescBody(MultipartRequestBody multipartRequestBody,
335             ByteBuf out) {
336      // The body of MultiPartPortDesc is empty
337     }
338
339     private static void encodeFlowBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {
340         MultipartRequestFlowCase flowCase = (MultipartRequestFlowCase) multipartRequestBody;
341         MultipartRequestFlow flow = flowCase.getMultipartRequestFlow();
342         output.writeByte(flow.getTableId().byteValue());
343         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_FLOW_BODY_01, output);
344         output.writeInt(flow.getOutPort().intValue());
345         output.writeInt(flow.getOutGroup().intValue());
346         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_FLOW_BODY_02, output);
347         output.writeLong(flow.getCookie().longValue());
348         output.writeLong(flow.getCookieMask().longValue());
349         MatchSerializer.encodeMatch(flow.getMatch(), output);
350     }
351
352     private static void encodeAggregateBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {
353         MultipartRequestAggregateCase aggregateCase = (MultipartRequestAggregateCase) multipartRequestBody;
354         MultipartRequestAggregate aggregate = aggregateCase.getMultipartRequestAggregate();
355         output.writeByte(aggregate.getTableId().byteValue());
356         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_AGREGGATE_BODY_01, output);
357         output.writeInt(aggregate.getOutPort().intValue());
358         output.writeInt(aggregate.getOutGroup().intValue());
359         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_AGREGGATE_BODY_02, output);
360         output.writeLong(aggregate.getCookie().longValue());
361         output.writeLong(aggregate.getCookieMask().longValue());
362         MatchSerializer.encodeMatch(aggregate.getMatch(), output);
363     }
364
365     private static void encodePortStatsBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {
366         MultipartRequestPortStatsCase portstatsCase = (MultipartRequestPortStatsCase) multipartRequestBody;
367         MultipartRequestPortStats portstats = portstatsCase.getMultipartRequestPortStats();
368         output.writeInt(portstats.getPortNo().intValue());
369         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_PORTSTATS_BODY, output);
370     }
371
372     private static void encodeQueueBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {
373         MultipartRequestQueueCase queueCase = (MultipartRequestQueueCase) multipartRequestBody;
374         MultipartRequestQueue queue = queueCase.getMultipartRequestQueue();
375         output.writeInt(queue.getPortNo().intValue());
376         output.writeInt(queue.getQueueId().intValue());
377     }
378
379     private static void encodeGroupStatsBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {
380         MultipartRequestGroupCase groupStatsCase = (MultipartRequestGroupCase) multipartRequestBody;
381         MultipartRequestGroup groupStats = groupStatsCase.getMultipartRequestGroup();
382         output.writeInt(groupStats.getGroupId().getValue().intValue());
383         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_GROUP_BODY, output);
384     }
385
386     private static void encodeMeterBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {
387         MultipartRequestMeterCase meterCase = (MultipartRequestMeterCase) multipartRequestBody;
388         MultipartRequestMeter meter = meterCase.getMultipartRequestMeter();
389         output.writeInt(meter.getMeterId().getValue().intValue());
390         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_METER_BODY, output);
391     }
392
393     private static void encodeMeterConfigBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {
394         MultipartRequestMeterConfigCase meterConfigCase = (MultipartRequestMeterConfigCase) multipartRequestBody;
395         MultipartRequestMeterConfig meterConfig = meterConfigCase.getMultipartRequestMeterConfig();
396         output.writeInt(meterConfig.getMeterId().getValue().intValue());
397         ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_METER_CONFIG_BODY, output);
398     }
399
400     private static void encodeExperimenterBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {
401         MultipartRequestExperimenterCase experimenterCase = (MultipartRequestExperimenterCase) multipartRequestBody;
402         MultipartRequestExperimenter experimenter = experimenterCase.getMultipartRequestExperimenter();
403         output.writeInt(experimenter.getExperimenter().intValue());
404         output.writeInt(experimenter.getExpType().intValue());
405         byte[] data = experimenter.getData();
406         if (data != null) {
407             output.writeBytes(data);
408         }
409     }
410
411     private static void encodeTableFeaturesBody(MultipartRequestBody multipartRequestBody, ByteBuf output) {
412         if (multipartRequestBody != null) {
413             MultipartRequestTableFeaturesCase tableFeaturesCase = (MultipartRequestTableFeaturesCase) multipartRequestBody;
414             MultipartRequestTableFeatures tableFeatures = tableFeaturesCase.getMultipartRequestTableFeatures();
415             if(tableFeatures.getTableFeatures() != null) {
416                 for (TableFeatures currTableFeature : tableFeatures.getTableFeatures()) {
417                     int length = computeSingleTableFeatureLength(currTableFeature);
418                     length += paddingNeeded(length);
419                     output.writeShort(length);
420                     output.writeByte(currTableFeature.getTableId());
421                     ByteBufUtils.padBuffer(PADDING_IN_MULTIPART_REQUEST_TABLE_FEATURES_BODY, output);
422                     output.writeBytes(currTableFeature.getName().getBytes());
423                     ByteBufUtils.padBuffer((32 - currTableFeature.getName().getBytes().length), output);
424                     output.writeLong(currTableFeature.getMetadataMatch().longValue());
425                     output.writeLong(currTableFeature.getMetadataWrite().longValue());
426                     output.writeInt(createTableConfigBitmask(currTableFeature.getConfig()));
427                     output.writeInt(currTableFeature.getMaxEntries().intValue());
428                     writeTableFeatureProperties(output, currTableFeature.getTableFeatureProperties());
429                 }
430             }
431         }
432     }
433
434     private static void writeTableFeatureProperties(ByteBuf output, List<TableFeatureProperties> props) {
435         if (props != null) {
436             for (TableFeatureProperties property : props) {
437                 TableFeaturesPropType type = property.getType();
438                 if (type.equals(TableFeaturesPropType.OFPTFPTINSTRUCTIONS)) {
439                     writeInstructionRelatedTableProperty(output, property, INSTRUCTIONS_CODE);
440                 } else if (type.equals(TableFeaturesPropType.OFPTFPTINSTRUCTIONSMISS)) {
441                     writeInstructionRelatedTableProperty(output, property, INSTRUCTIONS_MISS_CODE);
442                 } else if (type.equals(TableFeaturesPropType.OFPTFPTNEXTTABLES)) {
443                     writeNextTableRelatedTableProperty(output, property, NEXT_TABLE_CODE);
444                 } else if (type.equals(TableFeaturesPropType.OFPTFPTNEXTTABLESMISS)) {
445                     writeNextTableRelatedTableProperty(output, property, NEXT_TABLE_MISS_CODE);
446                 } else if (type.equals(TableFeaturesPropType.OFPTFPTWRITEACTIONS)) {
447                     writeActionsRelatedTableProperty(output, property, WRITE_ACTIONS_CODE);
448                 } else if (type.equals(TableFeaturesPropType.OFPTFPTWRITEACTIONSMISS)) {
449                     writeActionsRelatedTableProperty(output, property, WRITE_ACTIONS_MISS_CODE);
450                 } else if (type.equals(TableFeaturesPropType.OFPTFPTAPPLYACTIONS)) {
451                     writeActionsRelatedTableProperty(output, property, APPLY_ACTIONS_CODE);
452                 } else if (type.equals(TableFeaturesPropType.OFPTFPTAPPLYACTIONSMISS)) {
453                     writeActionsRelatedTableProperty(output, property, APPLY_ACTIONS_MISS_CODE);
454                 } else if (type.equals(TableFeaturesPropType.OFPTFPTMATCH)) {
455                     writeOxmRelatedTableProperty(output, property, MATCH_CODE);
456                 } else if (type.equals(TableFeaturesPropType.OFPTFPTWILDCARDS)) {
457                     writeOxmRelatedTableProperty(output, property, WILDCARDS_CODE);
458                 } else if (type.equals(TableFeaturesPropType.OFPTFPTWRITESETFIELD)) {
459                     writeOxmRelatedTableProperty(output, property, WRITE_SETFIELD_CODE);
460                 } else if (type.equals(TableFeaturesPropType.OFPTFPTWRITESETFIELDMISS)) {
461                     writeOxmRelatedTableProperty(output, property, WRITE_SETFIELD_MISS_CODE);
462                 } else if (type.equals(TableFeaturesPropType.OFPTFPTAPPLYSETFIELD)) {
463                     writeOxmRelatedTableProperty(output, property, APPLY_SETFIELD_CODE);
464                 } else if (type.equals(TableFeaturesPropType.OFPTFPTAPPLYSETFIELDMISS)) {
465                     writeOxmRelatedTableProperty(output, property, APPLY_SETFIELD_MISS_CODE);
466                 } else if (type.equals(TableFeaturesPropType.OFPTFPTEXPERIMENTER)) {
467                     writeExperimenterRelatedTableProperty(output, property, EXPERIMENTER_CODE);
468                 } else if (type.equals(TableFeaturesPropType.OFPTFPTEXPERIMENTERMISS)) {
469                     writeExperimenterRelatedTableProperty(output, property, EXPERIMENTER_MISS_CODE);
470                 }
471             }
472         }
473     }
474
475     private static void writeInstructionRelatedTableProperty(ByteBuf output,
476             TableFeatureProperties property, byte code) {
477         output.writeShort(code);
478         List<Instructions> instructions = property.
479                 getAugmentation(InstructionRelatedTableFeatureProperty.class).getInstructions();
480         int length = TABLE_FEAT_HEADER_LENGTH;
481         int padding = 0;
482         if (instructions != null) {
483             length += instructions.size() * STRUCTURE_HEADER_LENGTH;
484             padding = paddingNeeded(length);
485             output.writeShort(length);
486             InstructionsSerializer.encodeInstructionIds(instructions, output);
487         } else {
488             padding = paddingNeeded(length);
489             output.writeShort(length);
490         }
491         ByteBufUtils.padBuffer(padding, output);
492     }
493
494     private static void writeNextTableRelatedTableProperty(ByteBuf output,
495             TableFeatureProperties property, byte code) {
496         output.writeShort(code);
497         List<NextTableIds> nextTableIds = property.
498                 getAugmentation(NextTableRelatedTableFeatureProperty.class).getNextTableIds();
499         int length = TABLE_FEAT_HEADER_LENGTH;
500         int padding = 0;
501         if (nextTableIds != null) {
502             length += nextTableIds.size();
503             padding = paddingNeeded(length);
504             output.writeShort(length);
505             for (NextTableIds next : nextTableIds) {
506                 output.writeByte(next.getTableId());
507             }
508         } else {
509             padding = paddingNeeded(length); 
510             output.writeShort(length + padding);
511         }
512         ByteBufUtils.padBuffer(padding, output);
513     }
514
515     private static int paddingNeeded(int length) {
516         int paddingRemainder = length % EncodeConstants.PADDING;
517         int result = 0;
518         if (paddingRemainder != 0) {
519             result = EncodeConstants.PADDING - paddingRemainder;
520         }
521         return result;
522     }
523
524     private static void writeActionsRelatedTableProperty(ByteBuf output,
525             TableFeatureProperties property, byte code) {
526         output.writeShort(code);
527         List<ActionsList> actions = property.
528                 getAugmentation(ActionRelatedTableFeatureProperty.class).getActionsList();
529         int length = TABLE_FEAT_HEADER_LENGTH;
530         int padding = 0;
531         if (actions != null) {
532             length += actions.size() * STRUCTURE_HEADER_LENGTH;
533             padding += paddingNeeded(length);
534             output.writeShort(length);
535             ActionsSerializer.encodeActionIds(actions, output);
536         } else {
537             padding = paddingNeeded(length);
538             output.writeShort(length);
539         }
540         ByteBufUtils.padBuffer(padding, output);
541     }
542
543     private static void writeOxmRelatedTableProperty(ByteBuf output,
544             TableFeatureProperties property, byte code) {
545         output.writeShort(code);
546         List<MatchEntries> entries = property.
547                 getAugmentation(OxmRelatedTableFeatureProperty.class).getMatchEntries();
548         int length = TABLE_FEAT_HEADER_LENGTH;
549         int padding = 0;
550         if (entries != null) {
551             length += entries.size() * STRUCTURE_HEADER_LENGTH;
552             padding = paddingNeeded(length);
553             output.writeShort(length);
554             MatchSerializer.encodeMatchIds(entries, output);
555         } else {
556             padding = paddingNeeded(length);
557             output.writeShort(length);
558         }
559         ByteBufUtils.padBuffer(padding, output);
560     }
561
562     private static void writeExperimenterRelatedTableProperty(ByteBuf output,
563             TableFeatureProperties property, int code) {
564         output.writeShort(code);
565         ExperimenterRelatedTableFeatureProperty exp = property.
566                 getAugmentation(ExperimenterRelatedTableFeatureProperty.class);
567         byte[] data = exp.getData();
568         int length = TABLE_FEAT_HEADER_LENGTH + 2 * (EncodeConstants.SIZE_OF_INT_IN_BYTES);
569         if (data != null) {
570             output.writeShort(length + data.length);
571             output.writeInt(exp.getExperimenter().intValue());
572             output.writeInt(exp.getExpType().intValue());
573             output.writeBytes(data);
574         } else {
575             output.writeShort(length);
576             output.writeInt(exp.getExperimenter().intValue());
577             output.writeInt(exp.getExpType().intValue());
578         }
579     }
580
581     private static int createTableConfigBitmask(TableConfig tableConfig) {
582         int tableConfigBitmask = 0;
583         Map<Integer, Boolean> tableConfigMap = new HashMap<>();
584         tableConfigMap.put(3, tableConfig.isOFPTCDEPRECATEDMASK());
585
586         tableConfigBitmask = ByteBufUtils.fillBitMaskFromMap(tableConfigMap);
587         return tableConfigBitmask;
588     }
589 }