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