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