80ce60d74662c286c89b83381376927275f94960
[openflowjava.git] / openflow-protocol-impl / src / main / java / org / opendaylight / openflowjava / protocol / impl / util / InstructionsSerializer.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.util;
10
11 import io.netty.buffer.ByteBuf;
12
13 import java.util.List;
14
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ActionsInstruction;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ExperimenterInstruction;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MetadataInstruction;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MeterIdInstruction;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.TableIdInstruction;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.actions.ActionsList;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.ApplyActions;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.ClearActions;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.Experimenter;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.GotoTable;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.Meter;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.WriteActions;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.WriteMetadata;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.instruction.rev130731.instructions.Instructions;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.Instruction;
30
31 /**
32  * Serializes ofp_instruction (OpenFlow v 1.3) structure
33  * @author michal.polkorab
34  * @author timotej.kubas
35  */
36 public abstract class InstructionsSerializer {
37
38     private static final byte GOTO_TABLE_TYPE = 1;
39     private static final byte WRITE_METADATA_TYPE = 2;
40     private static final byte WRITE_ACTIONS_TYPE = 3;
41     private static final byte APPLY_ACTIONS_TYPE = 4;
42     private static final byte CLEAR_ACTIONS_TYPE = 5;
43     private static final byte METER_TYPE = 6;
44     private static final byte EXPERIMENTER_TYPE = 7;
45     private static final byte GOTO_TABLE_LENGTH = 8;
46     private static final byte WRITE_METADATA_LENGTH = 24;
47     private static final byte METER_LENGTH = 8;
48     private static final byte EXPERIMENTER_LENGTH = 8;
49     private static final byte ACTIONS_INSTRUCTION_LENGTH = 8;
50     private static final byte PADDING_IN_GOTO_TABLE = 3;
51     private static final byte PADDING_IN_WRITE_METADATA = 4;
52     private static final byte PADDING_IN_CLEAR_ACTIONS = 4;
53     private static final byte INSTRUCTION_IDS_LENGTH = 4;
54     private static final byte PADDING_IN_ACTIONS_INSTRUCTION = 4;
55     
56     /**
57      * Encodes instructions
58      * @param instructions List of instructions
59      * @param out output buffer
60      */
61     public static void encodeInstructions(List<Instructions> instructions, ByteBuf out) {
62         if (instructions != null) {
63             for (Instructions instruction : instructions) {
64                 Class<? extends Instruction> type = instruction.getType();
65                 if (type.isAssignableFrom(GotoTable.class)) {
66                     writeTypeAndLength(out, GOTO_TABLE_TYPE, GOTO_TABLE_LENGTH);
67                     out.writeByte(instruction.getAugmentation(TableIdInstruction.class).getTableId());
68                     ByteBufUtils.padBuffer(PADDING_IN_GOTO_TABLE, out);
69                 } else if (type.isAssignableFrom(WriteMetadata.class)) {
70                     writeTypeAndLength(out, WRITE_METADATA_TYPE, WRITE_METADATA_LENGTH);
71                     ByteBufUtils.padBuffer(PADDING_IN_WRITE_METADATA, out);
72                     MetadataInstruction metadata = instruction.getAugmentation(MetadataInstruction.class);
73                     out.writeBytes(metadata.getMetadata());
74                     out.writeBytes(metadata.getMetadataMask());
75                 } else if (type.isAssignableFrom(WriteActions.class)) {
76                     writeActionsInstruction(out, instruction, WRITE_ACTIONS_TYPE);
77                 } else if (type.isAssignableFrom(ApplyActions.class)) {
78                     writeActionsInstruction(out, instruction, APPLY_ACTIONS_TYPE);
79                 } else if (type.isAssignableFrom(ClearActions.class)) {
80                     writeTypeAndLength(out, CLEAR_ACTIONS_TYPE, ACTIONS_INSTRUCTION_LENGTH);
81                     ByteBufUtils.padBuffer(PADDING_IN_CLEAR_ACTIONS, out);
82                 } else if (type.isAssignableFrom(Meter.class)) {
83                     writeTypeAndLength(out, METER_TYPE, METER_LENGTH);
84                     out.writeInt(instruction.getAugmentation(MeterIdInstruction.class).getMeterId().intValue());
85                 } else if (type.isAssignableFrom(Experimenter.class)) {
86                     ExperimenterInstruction experimenter = instruction.getAugmentation(ExperimenterInstruction.class);
87                     byte[] data = experimenter.getData();
88                     writeTypeAndLength(out, EXPERIMENTER_TYPE, EXPERIMENTER_LENGTH + data.length);
89                     out.writeInt(experimenter.getExperimenter().intValue());
90                     out.writeBytes(data);
91                 }
92             }
93         }
94         
95     }
96     
97     /**
98      * Encodes instruction ids (for Multipart - TableFeatures messages)
99      * @param instructions List of instruction identifiers (without values)
100      * @param out output buffer
101      */
102     public static void encodeInstructionIds(List<Instructions> instructions, ByteBuf out) {
103         if (instructions != null) {
104             for (Instructions instruction : instructions) {
105                 Class<? extends Instruction> type = instruction.getType();
106                 if (type.isAssignableFrom(GotoTable.class)) {
107                     writeTypeAndLength(out, GOTO_TABLE_TYPE, INSTRUCTION_IDS_LENGTH);
108                 } else if (type.isAssignableFrom(WriteMetadata.class)) {
109                     writeTypeAndLength(out, WRITE_METADATA_TYPE, INSTRUCTION_IDS_LENGTH);
110                 } else if (type.isAssignableFrom(WriteActions.class)) {
111                     writeTypeAndLength(out, WRITE_ACTIONS_TYPE, INSTRUCTION_IDS_LENGTH);
112                 } else if (type.isAssignableFrom(ApplyActions.class)) {
113                     writeTypeAndLength(out, APPLY_ACTIONS_TYPE, INSTRUCTION_IDS_LENGTH);
114                 } else if (type.isAssignableFrom(ClearActions.class)) {
115                     writeTypeAndLength(out, CLEAR_ACTIONS_TYPE, INSTRUCTION_IDS_LENGTH);
116                 } else if (type.isAssignableFrom(Meter.class)) {
117                     writeTypeAndLength(out, METER_TYPE, INSTRUCTION_IDS_LENGTH);
118                 } else if (type.isAssignableFrom(Experimenter.class)) {
119                     ExperimenterInstruction experimenter = instruction.getAugmentation(ExperimenterInstruction.class);
120                     writeTypeAndLength(out, EXPERIMENTER_TYPE, EncodeConstants.EXPERIMENTER_IDS_LENGTH);
121                     out.writeInt(experimenter.getExperimenter().intValue());
122                 }
123             }
124         }
125     }
126
127     private static void writeTypeAndLength(ByteBuf out, int type, int length) {
128         out.writeShort(type);
129         out.writeShort(length);
130     }
131
132     private static void writeActionsInstruction(ByteBuf out,
133             Instructions instruction, int type) {
134         out.writeShort(type);
135         if (instruction.getAugmentation(ActionsInstruction.class) != null) {
136             List<ActionsList> actions = instruction.getAugmentation(ActionsInstruction.class).getActionsList();
137             out.writeShort(ACTIONS_INSTRUCTION_LENGTH + ActionsSerializer.computeLengthOfActions(actions));
138             ByteBufUtils.padBuffer(PADDING_IN_ACTIONS_INSTRUCTION, out);
139             ActionsSerializer.encodeActions(actions, out);
140         } else {
141             out.writeShort(ACTIONS_INSTRUCTION_LENGTH);
142             ByteBufUtils.padBuffer(PADDING_IN_ACTIONS_INSTRUCTION, out);
143         }
144     }
145     
146     /**
147      * Computes length of instructions
148      * @param instructions List of instructions
149      * @return length of instructions (in bytes)
150      */
151     public static int computeInstructionsLength(List<Instructions> instructions) {
152         int length = 0;
153         if (instructions != null) {
154             for (Instructions instruction : instructions) {
155                 Class<? extends Instruction> type = instruction.getType();
156                 if (type.isAssignableFrom(GotoTable.class)) {
157                     length += GOTO_TABLE_LENGTH;
158                 } else if (type.isAssignableFrom(WriteMetadata.class)) {
159                     length += WRITE_METADATA_LENGTH;
160                 } else if (type.isAssignableFrom(WriteActions.class)) {
161                     length += ACTIONS_INSTRUCTION_LENGTH;
162                     if (instruction.getAugmentation(ActionsInstruction.class) != null) {
163                         length += ActionsSerializer.computeLengthOfActions(
164                             instruction.getAugmentation(ActionsInstruction.class).getActionsList());
165                     }
166                 } else if (type.isAssignableFrom(ApplyActions.class)) {
167                     length += ACTIONS_INSTRUCTION_LENGTH;
168                     if (instruction.getAugmentation(ActionsInstruction.class) != null) {
169                         length += ActionsSerializer.computeLengthOfActions(
170                                 instruction.getAugmentation(ActionsInstruction.class).getActionsList());
171                     }
172                 } else if (type.isAssignableFrom(ClearActions.class)) {
173                     length += ACTIONS_INSTRUCTION_LENGTH;
174                 } else if (type.isAssignableFrom(Meter.class)) {
175                     length += METER_LENGTH;
176                 } else if (type.isAssignableFrom(Experimenter.class)) {
177                     ExperimenterInstruction experimenter = instruction.getAugmentation(ExperimenterInstruction.class);
178                     byte[] data = experimenter.getData();
179                     length += EXPERIMENTER_LENGTH + data.length;
180                 }
181             }
182         }
183         return length;
184     }
185 }