Merge "OPNFLWPLUG-898 Improve code quality in liblldp module"
[openflowplugin.git] / extension / openflowjava-extension-nicira / src / main / java / org / opendaylight / openflowjava / nx / codec / action / LearnCodecUtil.java
1 /*
2  * Copyright (c) 2016 Hewlett-Packard Enterprise 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 package org.opendaylight.openflowjava.nx.codec.action;
9
10 import io.netty.buffer.ByteBuf;
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.List;
14 import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.action.container.action.choice.ActionLearn;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModAddMatchFromFieldCase;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModAddMatchFromFieldCaseBuilder;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModAddMatchFromValueCase;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModAddMatchFromValueCaseBuilder;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModCopyFieldIntoFieldCase;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModCopyFieldIntoFieldCaseBuilder;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModCopyValueIntoFieldCase;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModCopyValueIntoFieldCaseBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModOutputToPortCase;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.FlowModOutputToPortCaseBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.add.match.from.field._case.FlowModAddMatchFromField;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.add.match.from.field._case.FlowModAddMatchFromFieldBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.add.match.from.value._case.FlowModAddMatchFromValue;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.add.match.from.value._case.FlowModAddMatchFromValueBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.copy.field.into.field._case.FlowModCopyFieldIntoField;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.copy.field.into.field._case.FlowModCopyFieldIntoFieldBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.copy.value.into.field._case.FlowModCopyValueIntoField;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.copy.value.into.field._case.FlowModCopyValueIntoFieldBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.output.to.port._case.FlowModOutputToPort;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.flow.mod.spec.flow.mod.spec.flow.mod.output.to.port._case.FlowModOutputToPortBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.learn.grouping.NxActionLearnBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.learn.grouping.nx.action.learn.FlowMods;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.action.rev140421.ofj.nx.action.learn.grouping.nx.action.learn.FlowModsBuilder;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 public final class LearnCodecUtil {
43
44     private static final Logger LOG = LoggerFactory.getLogger(LearnCodecUtil.class);
45     public static final int HEADER_LENGTH = 32;
46     private static final short SRC_MASK = 0x2000;
47     private static final short DST_MASK = 0x1800;
48     private static final short NUM_BITS_MASK = 0x07FF;
49     private static final int SRC_POS = 13;
50     private static final int DST_POS = 11;
51     private static final int FROM_FIELD_LENGTH = 14;
52     private static final int FROM_VALUE_LENGTH = 10;
53     private static final int TO_PORT_LENGTH = 8;
54     private static final int EMPTY_FLOW_MOD_LENGTH = 2;
55     private static short length;
56
57     private LearnCodecUtil() {
58     }
59
60     static short deserializeHeader(ByteBuf message) {
61         // size of experimenter type
62         message.skipBytes(EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
63         // size of length
64         short messageLength = message.readShort();
65         // vendor id
66         message.skipBytes(EncodeConstants.SIZE_OF_INT_IN_BYTES);
67         // subtype
68         message.skipBytes(EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
69         return messageLength;
70     }
71
72     /*
73      *                                 SERIALIZATION
74     */
75
76     static void serializeLearnHeader(final ByteBuf outBuffer, ActionLearn action) {
77         outBuffer.writeShort(action.getNxActionLearn().getIdleTimeout().shortValue());
78         outBuffer.writeShort(action.getNxActionLearn().getHardTimeout().shortValue());
79         outBuffer.writeShort(action.getNxActionLearn().getPriority().shortValue());
80         outBuffer.writeLong(action.getNxActionLearn().getCookie().longValue());
81         outBuffer.writeShort(action.getNxActionLearn().getFlags().shortValue());
82         outBuffer.writeByte(action.getNxActionLearn().getTableId().byteValue());
83         outBuffer.writeZero(1);
84         outBuffer.writeShort(action.getNxActionLearn().getFinIdleTimeout().shortValue());
85         outBuffer.writeShort(action.getNxActionLearn().getFinHardTimeout().shortValue());
86     }
87
88     static void serializeFlowMods(final ByteBuf outBuffer, ActionLearn action) {
89         if (action.getNxActionLearn().getFlowMods() != null) {
90             for (FlowMods flowMod : action.getNxActionLearn().getFlowMods()) {
91                 if (flowMod.getFlowModSpec() instanceof FlowModAddMatchFromFieldCase) {
92                     FlowModAddMatchFromField flowModSpecFromField = ((FlowModAddMatchFromFieldCase) flowMod
93                             .getFlowModSpec()).getFlowModAddMatchFromField();
94                     toFlowModSpecHeader(flowModSpecFromField, outBuffer);
95                     outBuffer.writeInt(flowModSpecFromField.getSrcField().intValue());
96                     outBuffer.writeShort(flowModSpecFromField.getSrcOfs().shortValue());
97                     outBuffer.writeInt(flowModSpecFromField.getDstField().intValue());
98                     outBuffer.writeShort(flowModSpecFromField.getDstOfs().shortValue());
99                 } else if (flowMod.getFlowModSpec() instanceof FlowModAddMatchFromValueCase) {
100                     FlowModAddMatchFromValue flowModSpec = ((FlowModAddMatchFromValueCase) flowMod.getFlowModSpec())
101                             .getFlowModAddMatchFromValue();
102                     toFlowModSpecHeader(flowModSpec, outBuffer);
103                     outBuffer.writeShort(flowModSpec.getValue().shortValue());
104                     outBuffer.writeInt(flowModSpec.getSrcField().intValue());
105                     outBuffer.writeShort(flowModSpec.getSrcOfs().shortValue());
106
107                 } else if (flowMod.getFlowModSpec() instanceof FlowModCopyFieldIntoFieldCase) {
108                     FlowModCopyFieldIntoField flowModSpec = ((FlowModCopyFieldIntoFieldCase) flowMod.getFlowModSpec())
109                             .getFlowModCopyFieldIntoField();
110                     toFlowModSpecHeader(flowModSpec, outBuffer);
111                     outBuffer.writeInt(flowModSpec.getSrcField().intValue());
112                     outBuffer.writeShort(flowModSpec.getSrcOfs().shortValue());
113                     outBuffer.writeInt(flowModSpec.getDstField().intValue());
114                     outBuffer.writeShort(flowModSpec.getDstOfs().shortValue());
115
116                 } else if (flowMod.getFlowModSpec() instanceof FlowModCopyValueIntoFieldCase) {
117                     FlowModCopyValueIntoField flowModSpec = ((FlowModCopyValueIntoFieldCase) flowMod.getFlowModSpec())
118                             .getFlowModCopyValueIntoField();
119                     toFlowModSpecHeader(flowModSpec, outBuffer);
120                     outBuffer.writeShort(flowModSpec.getValue().shortValue());
121                     outBuffer.writeInt(flowModSpec.getDstField().intValue());
122                     outBuffer.writeShort(flowModSpec.getDstOfs().shortValue());
123
124                 } else if (flowMod.getFlowModSpec() instanceof FlowModOutputToPortCase) {
125                     FlowModOutputToPort flowModSpec = ((FlowModOutputToPortCase) flowMod.getFlowModSpec())
126                             .getFlowModOutputToPort();
127                     toFlowModSpecHeader(flowModSpec, outBuffer);
128                     outBuffer.writeInt(flowModSpec.getSrcField().intValue());
129                     outBuffer.writeShort(flowModSpec.getSrcOfs().shortValue());
130                 }
131             }
132         }
133     }
134
135     private static void toFlowModSpecHeader(FlowModOutputToPort flowModSpec, ByteBuf outBuffer) {
136         serializeFlowModSpecHeader(0,2,(short)(int)flowModSpec.getFlowModNumBits(), outBuffer);
137     }
138
139     private static void toFlowModSpecHeader(FlowModCopyValueIntoField flowModSpec, ByteBuf outBuffer) {
140         serializeFlowModSpecHeader(1,1,(short)(int)flowModSpec.getFlowModNumBits(), outBuffer);
141     }
142
143     private static void toFlowModSpecHeader(FlowModCopyFieldIntoField flowModSpec, ByteBuf outBuffer) {
144         serializeFlowModSpecHeader(0,1,(short)(int)flowModSpec.getFlowModNumBits(), outBuffer);
145     }
146
147     private static void toFlowModSpecHeader(FlowModAddMatchFromValue flowModSpec, ByteBuf outBuffer) {
148         serializeFlowModSpecHeader(1,0,(short)(int)flowModSpec.getFlowModNumBits(), outBuffer);
149     }
150
151     private static void toFlowModSpecHeader(FlowModAddMatchFromField flowModSpec, ByteBuf outBuffer) {
152         serializeFlowModSpecHeader(0,0,(short)(int)flowModSpec.getFlowModNumBits(), outBuffer);
153     }
154
155     private static void serializeFlowModSpecHeader(int src, int dst, short bitNum, ByteBuf outBuffer) {
156         short value = 0;
157         value |= src << SRC_POS;
158         value |= dst << DST_POS;
159         value |= bitNum;
160         outBuffer.writeShort(value);
161     }
162
163     static int calcLength(ActionLearn action) {
164         int actionLength = HEADER_LENGTH;
165         if (action.getNxActionLearn().getFlowMods() == null) {
166             return actionLength;
167         }
168         for (FlowMods flowMod : action.getNxActionLearn().getFlowMods()) {
169             if (flowMod.getFlowModSpec() instanceof FlowModAddMatchFromFieldCase) {
170                 actionLength += FROM_FIELD_LENGTH;
171             } else if (flowMod.getFlowModSpec() instanceof FlowModAddMatchFromValueCase) {
172                 actionLength += FROM_VALUE_LENGTH;
173             } else if (flowMod.getFlowModSpec() instanceof FlowModCopyFieldIntoFieldCase) {
174                 actionLength += FROM_FIELD_LENGTH;
175             } else if (flowMod.getFlowModSpec() instanceof FlowModCopyValueIntoFieldCase) {
176                 actionLength += FROM_VALUE_LENGTH;
177             } else if (flowMod.getFlowModSpec() instanceof FlowModOutputToPortCase) {
178                 actionLength += TO_PORT_LENGTH;
179             }
180         }
181
182         return actionLength;
183     }
184
185     /*
186      *                                 DESERIALIZATION
187     */
188
189     static void deserializeLearnHeader(final ByteBuf message, NxActionLearnBuilder nxActionLearnBuilder) {
190         nxActionLearnBuilder.setIdleTimeout(message.readUnsignedShort());
191         nxActionLearnBuilder.setHardTimeout(message.readUnsignedShort());
192         nxActionLearnBuilder.setPriority(message.readUnsignedShort());
193         nxActionLearnBuilder.setCookie(BigInteger.valueOf(message.readLong()));
194         nxActionLearnBuilder.setFlags(message.readUnsignedShort());
195         nxActionLearnBuilder.setTableId(message.readUnsignedByte());
196         message.skipBytes(1);
197         nxActionLearnBuilder.setFinIdleTimeout(message.readUnsignedShort());
198         nxActionLearnBuilder.setFinHardTimeout(message.readUnsignedShort());
199     }
200
201     static synchronized void buildFlowModSpecs(NxActionLearnBuilder nxActionLearnBuilder, ByteBuf message,
202             short messageLength) {
203         LearnCodecUtil.length = messageLength;
204         List<FlowMods> flowModeList = new ArrayList<>();
205
206         while (LearnCodecUtil.length > 0) {
207             FlowMods flowMod = readFlowMod(message);
208
209             if (flowMod != null) {
210                 flowModeList.add(flowMod);
211             } else {
212                 LOG.trace("skipping padding bytes");
213             }
214         }
215
216         if (LearnCodecUtil.length != 0) {
217             LOG.error("Learn Codec read " + Math.abs(messageLength)
218                     + " bytes more than needed from stream. Packet might be corrupted");
219         }
220         nxActionLearnBuilder.setFlowMods(flowModeList);
221     }
222
223     private static FlowMods readFlowMod(ByteBuf message) {
224         short header = message.readShort();
225         length -= EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
226         if (header == 0) {
227             return null;
228         }
229
230         short src = (short) ((header & SRC_MASK) >> SRC_POS);
231         short dst = (short) ((header & DST_MASK) >> DST_POS);
232         short numBits = (short) (header & NUM_BITS_MASK);
233
234         if (src == 0 && dst == 0 && numBits != 0) {
235             return readFlowModAddMatchFromField(message, numBits);
236         } else if (src == 0 && dst == 0) {
237             message.skipBytes(EMPTY_FLOW_MOD_LENGTH);
238             length -= EMPTY_FLOW_MOD_LENGTH;
239         } else if (src == 1 && dst == 0) {
240             return readFlowModAddMatchFromValue(message, numBits);
241         } else if (src == 0 && dst == 1) {
242             return readFlowModCopyFromField(message, numBits);
243         } else if (src == 1 && dst == 1) {
244             return readFlowModCopyFromValue(message, numBits);
245         } else if (src == 0 && dst == 2) {
246             return readFlowToPort(message, numBits);
247         }
248         return null;
249     }
250
251
252
253     private static FlowMods readFlowModAddMatchFromField(ByteBuf message, short numBits) {
254         FlowModAddMatchFromFieldBuilder builder = new FlowModAddMatchFromFieldBuilder();
255         builder.setSrcField(message.readUnsignedInt());
256         builder.setSrcOfs((int) message.readShort());
257         builder.setDstField(message.readUnsignedInt());
258         builder.setDstOfs((int) message.readShort());
259         builder.setFlowModNumBits((int) numBits);
260         length -= FROM_FIELD_LENGTH - EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
261
262         FlowModsBuilder flowModsBuilder = new FlowModsBuilder();
263         FlowModAddMatchFromFieldCaseBuilder caseBuilder = new FlowModAddMatchFromFieldCaseBuilder();
264         caseBuilder.setFlowModAddMatchFromField(builder.build());
265         flowModsBuilder.setFlowModSpec(caseBuilder.build());
266         return flowModsBuilder.build();
267     }
268
269     private static FlowMods readFlowModAddMatchFromValue(ByteBuf message, short numBits) {
270         FlowModAddMatchFromValueBuilder builder = new FlowModAddMatchFromValueBuilder();
271         builder.setValue(message.readUnsignedShort());
272         builder.setSrcField(message.readUnsignedInt());
273         builder.setSrcOfs((int) message.readShort());
274         builder.setFlowModNumBits((int) numBits);
275         length -= FROM_VALUE_LENGTH - EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
276
277         FlowModsBuilder flowModsBuilder = new FlowModsBuilder();
278         FlowModAddMatchFromValueCaseBuilder caseBuilder = new FlowModAddMatchFromValueCaseBuilder();
279         caseBuilder.setFlowModAddMatchFromValue(builder.build());
280         flowModsBuilder.setFlowModSpec(caseBuilder.build());
281         return flowModsBuilder.build();
282     }
283
284     private static FlowMods readFlowModCopyFromField(ByteBuf message, short numBits) {
285         FlowModCopyFieldIntoFieldBuilder builder = new FlowModCopyFieldIntoFieldBuilder();
286         builder.setSrcField(message.readUnsignedInt());
287         builder.setSrcOfs((int) message.readShort());
288         builder.setDstField(message.readUnsignedInt());
289         builder.setDstOfs((int) message.readShort());
290         builder.setFlowModNumBits((int) numBits);
291         length -= FROM_FIELD_LENGTH - EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
292
293         FlowModsBuilder flowModsBuilder = new FlowModsBuilder();
294         FlowModCopyFieldIntoFieldCaseBuilder caseBuilder = new FlowModCopyFieldIntoFieldCaseBuilder();
295         caseBuilder.setFlowModCopyFieldIntoField(builder.build());
296         flowModsBuilder.setFlowModSpec(caseBuilder.build());
297         return flowModsBuilder.build();
298     }
299
300     private static FlowMods readFlowModCopyFromValue(ByteBuf message, short numBits) {
301         FlowModCopyValueIntoFieldBuilder builder = new FlowModCopyValueIntoFieldBuilder();
302         builder.setValue(message.readUnsignedShort());
303         builder.setDstField(message.readUnsignedInt());
304         builder.setDstOfs((int) message.readShort());
305         builder.setFlowModNumBits((int) numBits);
306         length -= FROM_VALUE_LENGTH - EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
307
308         FlowModsBuilder flowModsBuilder = new FlowModsBuilder();
309         FlowModCopyValueIntoFieldCaseBuilder caseBuilder = new FlowModCopyValueIntoFieldCaseBuilder();
310         caseBuilder.setFlowModCopyValueIntoField(builder.build());
311         flowModsBuilder.setFlowModSpec(caseBuilder.build());
312         return flowModsBuilder.build();
313     }
314
315     private static FlowMods readFlowToPort(ByteBuf message, short numBits) {
316         FlowModOutputToPortBuilder builder = new FlowModOutputToPortBuilder();
317         builder.setSrcField(message.readUnsignedInt());
318         builder.setSrcOfs((int) message.readShort());
319         builder.setFlowModNumBits((int) numBits);
320         length -= TO_PORT_LENGTH - EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
321
322         FlowModsBuilder flowModsBuilder = new FlowModsBuilder();
323         FlowModOutputToPortCaseBuilder caseBuilder = new FlowModOutputToPortCaseBuilder();
324         caseBuilder.setFlowModOutputToPort(builder.build());
325         flowModsBuilder.setFlowModSpec(caseBuilder.build());
326         return flowModsBuilder.build();
327     }
328 }