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