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