Added validation
[openflowjava.git] / openflow-protocol-impl / src / main / java / org / opendaylight / openflowjava / protocol / impl / util / ActionsSerializer.java
1 /* Copyright (C)2013 Pantheon Technologies, s.r.o. All rights reserved. */\r
2 package org.opendaylight.openflowjava.protocol.impl.util;\r
3 \r
4 import io.netty.buffer.ByteBuf;\r
5 \r
6 import java.util.List;\r
7 \r
8 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.EthertypeAction;\r
9 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ExperimenterAction;\r
10 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.GroupIdAction;\r
11 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MaxLengthAction;\r
12 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MplsTtlAction;\r
13 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.NwTtlAction;\r
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.OxmFieldsAction;\r
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PortAction;\r
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.QueueIdAction;\r
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.CopyTtlIn;\r
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.CopyTtlOut;\r
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.DecMplsTtl;\r
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.DecNwTtl;\r
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.Experimenter;\r
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.Group;\r
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.Output;\r
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.PopMpls;\r
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.PopPbb;\r
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.PopVlan;\r
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.PushMpls;\r
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.PushPbb;\r
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.PushVlan;\r
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.SetField;\r
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.SetMplsTtl;\r
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.SetNwTtl;\r
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.SetQueue;\r
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.actions.ActionsList;\r
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.actions.actions.list.Action;\r
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.oxm.fields.MatchEntries;\r
37 \r
38 /**\r
39  * Serializes ofp_actions (OpenFlow v1.3)\r
40  * @author michal.polkorab\r
41  * @author timotej.kubas\r
42  */\r
43 public abstract class ActionsSerializer {\r
44 \r
45     /**\r
46      * Encodes actions to ByteBuf\r
47      * @param actionsList list of actions to be encoded\r
48      * @param outBuffer output ByteBuf\r
49      */\r
50     public static void encodeActions(List<ActionsList> actionsList, ByteBuf outBuffer) {\r
51         if (actionsList == null) {\r
52             return;\r
53         }\r
54         for (ActionsList list : actionsList) {\r
55             Action action = list.getAction();\r
56             if (action.getType().isAssignableFrom(Output.class)) {\r
57                 encodeOutputAction(action, outBuffer);\r
58             } else if (action.getType().isAssignableFrom(CopyTtlOut.class)) {\r
59                 encodeCopyTtlOutAction(outBuffer);\r
60             } else if (action.getType().isAssignableFrom(CopyTtlIn.class)) {\r
61                 encodeCopyTtlInAction(outBuffer);\r
62             } else if (action.getType().isAssignableFrom(SetMplsTtl.class)) {\r
63                 encodeSetMplsTtltAction(action, outBuffer);\r
64             } else if (action.getType().isAssignableFrom(DecMplsTtl.class)) {\r
65                 encodeDecMplsTtlAction(outBuffer);\r
66             } else if (action.getType().isAssignableFrom(PushVlan.class)) {\r
67                 encodePushVlanAction(action, outBuffer);\r
68             } else if (action.getType().isAssignableFrom(PopVlan.class)) {\r
69                 encodePopVlanAction(outBuffer);\r
70             } else if (action.getType().isAssignableFrom(PushMpls.class)) {\r
71                 encodePushMplsAction(action, outBuffer);\r
72             } else if (action.getType().isAssignableFrom(PopMpls.class)) {\r
73                 encodePopMplsAction(action, outBuffer);\r
74             } else if (action.getType().isAssignableFrom(SetQueue.class)) {\r
75                 encodeSetQueueAction(action, outBuffer);\r
76             } else if (action.getType().isAssignableFrom(Group.class)) {\r
77                 encodeGroupAction(action, outBuffer);\r
78             } else if (action.getType().isAssignableFrom(SetNwTtl.class)) {\r
79                 encodeSetNwTtlAction(action, outBuffer);\r
80             } else if (action.getType().isAssignableFrom(DecNwTtl.class)) {\r
81                 encodeDecNwTtlAction(outBuffer);\r
82             } else if (action.getType().isAssignableFrom(SetField.class)) {\r
83                 encodeSetFieldAction(action, outBuffer);\r
84             } else if (action.getType().isAssignableFrom(PushPbb.class)) {\r
85                 encodePushPbbAction(action, outBuffer);\r
86             } else if (action.getType().isAssignableFrom(PopPbb.class)) {\r
87                 encodePopPbbAction(outBuffer);\r
88             } else if (action.getType().isAssignableFrom(Experimenter.class)) {\r
89                 encodeExperimenterAction(action, outBuffer);\r
90             } \r
91         }\r
92     }\r
93 \r
94     private static void encodeOutputAction(Action action, ByteBuf outBuffer) {\r
95         final byte OUTPUT_CODE = 0;\r
96         final byte OUTPUT_LENGTH = 16;\r
97         final byte OUTPUT_PADDING = 6;\r
98         outBuffer.writeShort(OUTPUT_CODE);\r
99         outBuffer.writeShort(OUTPUT_LENGTH);\r
100         PortAction port = action.getAugmentation(PortAction.class);\r
101         outBuffer.writeInt(port.getPort().getValue().intValue());\r
102         MaxLengthAction maxlength = action.getAugmentation(MaxLengthAction.class);\r
103         outBuffer.writeShort(maxlength.getMaxLength());\r
104         ByteBufUtils.padBuffer(OUTPUT_PADDING, outBuffer);\r
105     }\r
106 \r
107     private static void encodeCopyTtlOutAction(ByteBuf outBuffer) {\r
108         final byte COPY_TTL_OUT_CODE = 11;\r
109         outBuffer.writeShort(COPY_TTL_OUT_CODE);\r
110         encodeRestOfActionHeader(outBuffer);\r
111     }\r
112     \r
113     private static void encodeCopyTtlInAction(ByteBuf outBuffer) {\r
114         final byte COPY_TTL_IN_CODE = 12;\r
115         outBuffer.writeShort(COPY_TTL_IN_CODE);\r
116         encodeRestOfActionHeader(outBuffer);\r
117     }\r
118     \r
119     private static void encodeSetMplsTtltAction(Action action, ByteBuf outBuffer) {\r
120         final byte SET_MPLS_TTL_CODE = 15;\r
121         final byte SET_MPLS_TTL_LENGTH = 8;\r
122         final byte SET_MPLS_TTL_PADDING = 3;\r
123         outBuffer.writeShort(SET_MPLS_TTL_CODE);\r
124         outBuffer.writeShort(SET_MPLS_TTL_LENGTH);\r
125         MplsTtlAction mplsTtl = action.getAugmentation(MplsTtlAction.class);\r
126         outBuffer.writeByte(mplsTtl.getMplsTtl());\r
127         ByteBufUtils.padBuffer(SET_MPLS_TTL_PADDING, outBuffer);\r
128     }\r
129     \r
130     private static void encodeDecMplsTtlAction(ByteBuf outBuffer) {\r
131         final byte DEC_MPLS_TTL_CODE = 16;\r
132         outBuffer.writeShort(DEC_MPLS_TTL_CODE);\r
133         encodeRestOfActionHeader(outBuffer);\r
134     }\r
135     \r
136     private static void encodePushVlanAction(Action action, ByteBuf outBuffer) {\r
137         final byte PUSH_VLAN_CODE = 17;\r
138         outBuffer.writeShort(PUSH_VLAN_CODE);\r
139         encodeCommonEthertype(action, outBuffer);\r
140     }\r
141 \r
142     private static void encodePopVlanAction(ByteBuf outBuffer) {\r
143         final byte POP_VLAN_CODE = 18;\r
144         outBuffer.writeShort(POP_VLAN_CODE);\r
145         encodeRestOfActionHeader(outBuffer);\r
146     }\r
147     \r
148     private static void encodePushMplsAction(Action action, ByteBuf outBuffer) {\r
149         final byte PUSH_MPLS_CODE = 19;\r
150         outBuffer.writeShort(PUSH_MPLS_CODE);\r
151         encodeCommonEthertype(action, outBuffer);\r
152     }\r
153     \r
154     private static void encodePopMplsAction(Action action, ByteBuf outBuffer) {\r
155         final byte POP_MPLS_CODE = 20;\r
156         outBuffer.writeShort(POP_MPLS_CODE);\r
157         encodeCommonEthertype(action, outBuffer);\r
158     }\r
159     \r
160     private static void encodeSetQueueAction(Action action, ByteBuf outBuffer) {\r
161         final byte SET_QUEUE_CODE = 21;\r
162         final byte SET_QUEUE_LENGTH = 8;\r
163         outBuffer.writeShort(SET_QUEUE_CODE);\r
164         outBuffer.writeShort(SET_QUEUE_LENGTH);\r
165         QueueIdAction queueId = action.getAugmentation(QueueIdAction.class);\r
166         outBuffer.writeInt(queueId.getQueueId().intValue());\r
167     }\r
168 \r
169     private static void encodeGroupAction(Action action, ByteBuf outBuffer) {\r
170         final byte GROUP_CODE = 22;\r
171         final byte GROUP_LENGTH = 8;\r
172         outBuffer.writeShort(GROUP_CODE);\r
173         outBuffer.writeShort(GROUP_LENGTH);\r
174         GroupIdAction groupId = action.getAugmentation(GroupIdAction.class);\r
175         outBuffer.writeInt(groupId.getGroupId().intValue());\r
176     }\r
177     \r
178     private static void encodeSetNwTtlAction(Action action, ByteBuf outBuffer) {\r
179         final byte SET_NW_TTL_CODE = 23;\r
180         final byte SET_NW_TTL_LENGTH = 8;\r
181         final byte SET_NW_TTL_PADDING = 3;\r
182         outBuffer.writeShort(SET_NW_TTL_CODE);\r
183         outBuffer.writeShort(SET_NW_TTL_LENGTH);\r
184         NwTtlAction nwTtl = action.getAugmentation(NwTtlAction.class);\r
185         outBuffer.writeByte(nwTtl.getNwTtl());\r
186         ByteBufUtils.padBuffer(SET_NW_TTL_PADDING, outBuffer);\r
187     }\r
188     \r
189     private static void encodeDecNwTtlAction(ByteBuf outBuffer) {\r
190         final byte DEC_NW_TTL_CODE = 24;\r
191         outBuffer.writeShort(DEC_NW_TTL_CODE);\r
192         encodeRestOfActionHeader(outBuffer);\r
193     }\r
194     \r
195     private static void encodeSetFieldAction(Action action, ByteBuf outBuffer) {\r
196         final int SET_FIELD_CODE = 25;\r
197         final byte SET_FIELD_HEADER_LENGTH = 4; // only type and length\r
198         OxmFieldsAction oxmField = action.getAugmentation(OxmFieldsAction.class);\r
199         int length = MatchSerializer.computeMatchEntriesLength(oxmField.getMatchEntries()) + SET_FIELD_HEADER_LENGTH;\r
200         outBuffer.writeShort(SET_FIELD_CODE);\r
201         int paddingRemainder = length % EncodeConstants.PADDING;\r
202         if (paddingRemainder != 0) {\r
203             length += EncodeConstants.PADDING - paddingRemainder;\r
204         }\r
205         outBuffer.writeShort(length);\r
206         MatchSerializer.encodeMatchEntries(oxmField.getMatchEntries(), outBuffer);\r
207         ByteBufUtils.padBuffer(EncodeConstants.PADDING - paddingRemainder, outBuffer);\r
208     }\r
209     \r
210     private static void encodePushPbbAction(Action action, ByteBuf outBuffer) {\r
211         final byte PUSH_PBB_CODE = 26;\r
212         outBuffer.writeShort(PUSH_PBB_CODE);\r
213         encodeCommonEthertype(action, outBuffer);\r
214     }\r
215     \r
216     private static void encodePopPbbAction(ByteBuf outBuffer) {\r
217         final byte POP_PBB_CODE = 27;\r
218         outBuffer.writeShort(POP_PBB_CODE);\r
219         encodeRestOfActionHeader(outBuffer);\r
220     }\r
221 \r
222     private static void encodeExperimenterAction(Action action, ByteBuf outBuffer) {\r
223         final int EXPERIMENTER_CODE = 65535; // 0xFFFF\r
224         final byte EXPERIMENTER_LENGTH = 8;\r
225         outBuffer.writeShort(EXPERIMENTER_CODE);\r
226         outBuffer.writeShort(EXPERIMENTER_LENGTH);\r
227         ExperimenterAction experimenter = action.getAugmentation(ExperimenterAction.class);\r
228         outBuffer.writeInt(experimenter.getExperimenter().intValue());\r
229     }\r
230     \r
231     private static void encodeRestOfActionHeader(ByteBuf outBuffer) {\r
232         final byte ACTION_HEADER_LENGTH = 8;\r
233         final byte PADDING_IN_ACTION_HEADER = 4;\r
234         outBuffer.writeShort(ACTION_HEADER_LENGTH);\r
235         ByteBufUtils.padBuffer(PADDING_IN_ACTION_HEADER, outBuffer);\r
236     }\r
237     \r
238     private static void encodeCommonEthertype(Action action, ByteBuf outBuffer) {\r
239         final byte LENGTH_OF_ETHERTYPE_ACTION = 8;\r
240         final byte ETHERTYPE_ACTION_PADDING = 2;        \r
241         EthertypeAction ethertype = action.getAugmentation(EthertypeAction.class);\r
242         \r
243         if (null != ethertype && null != ethertype.getEthertype()) {\r
244             outBuffer.writeShort(LENGTH_OF_ETHERTYPE_ACTION);\r
245             \r
246             outBuffer.writeShort(ethertype.getEthertype().getValue());\r
247             ByteBufUtils.padBuffer(ETHERTYPE_ACTION_PADDING, outBuffer);\r
248         }\r
249     }\r
250     \r
251     /**\r
252      * Computes length of actions\r
253      * @param actionsList list of actions\r
254      * @return actions length\r
255      */\r
256     public static int computeLengthOfActions(List<ActionsList> actionsList) {\r
257         final byte OUTPUT_LENGTH = 16;\r
258         final byte LENGTH_OF_OTHER_ACTIONS = 8;\r
259         final byte ACTION_HEADER_LENGTH = 4;\r
260         int lengthOfActions = 0;\r
261         if (actionsList != null) {\r
262             for (ActionsList list : actionsList) {\r
263                 Action action = list.getAction();\r
264                 if (action.getType().isAssignableFrom(Output.class)) {\r
265                     lengthOfActions += OUTPUT_LENGTH;\r
266                 } else if (action.getType().isAssignableFrom(SetField.class)){\r
267                     List<MatchEntries> entries = action.getAugmentation(OxmFieldsAction.class).getMatchEntries();\r
268                     int actionLength = ACTION_HEADER_LENGTH + MatchSerializer.computeMatchEntriesLength(entries);\r
269                     lengthOfActions += actionLength;\r
270                     int paddingRemainder = actionLength % EncodeConstants.PADDING;\r
271                     if ((paddingRemainder) != 0) {\r
272                         lengthOfActions += EncodeConstants.PADDING - paddingRemainder;\r
273                     }\r
274                 } else {\r
275                     lengthOfActions += LENGTH_OF_OTHER_ACTIONS;\r
276                 }\r
277             }\r
278         }\r
279         return lengthOfActions;\r
280     }\r
281 }\r