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