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