2 * Copyright (c) 2013 Pantheon Technologies s.r.o. and others. All rights reserved.
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
9 package org.opendaylight.openflowjava.protocol.impl.util;
11 import io.netty.buffer.ByteBuf;
13 import java.util.List;
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;
46 * Serializes ofp_actions (OpenFlow v1.3)
47 * @author michal.polkorab
48 * @author timotej.kubas
50 public abstract class ActionsSerializer {
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;
88 * Encodes actions to ByteBuf
89 * @param actionsList list of actions to be encoded
90 * @param outBuffer output ByteBuf
92 public static void encodeActions(List<ActionsList> actionsList, ByteBuf outBuffer) {
93 if (actionsList == null) {
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);
137 * Encodes action ids to ByteBuf (for Multipart - TableFeatures messages)
138 * @param actionsList list of actions to be encoded
139 * @param outBuffer output ByteBuf
141 public static void encodeActionIds(List<ActionsList> actionsList, ByteBuf outBuffer) {
142 if (actionsList == null) {
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());
187 private static void writeTypeAndLength(ByteBuf out, int type, int length) {
188 out.writeShort(type);
189 out.writeShort(length);
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);
202 private static void encodeCopyTtlOutAction(ByteBuf outBuffer) {
203 outBuffer.writeShort(COPY_TTL_OUT_CODE);
204 encodeRestOfActionHeader(outBuffer);
207 private static void encodeCopyTtlInAction(ByteBuf outBuffer) {
208 outBuffer.writeShort(COPY_TTL_IN_CODE);
209 encodeRestOfActionHeader(outBuffer);
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);
220 private static void encodeDecMplsTtlAction(ByteBuf outBuffer) {
221 outBuffer.writeShort(DEC_MPLS_TTL_CODE);
222 encodeRestOfActionHeader(outBuffer);
225 private static void encodePushVlanAction(Action action, ByteBuf outBuffer) {
226 outBuffer.writeShort(PUSH_VLAN_CODE);
227 encodeCommonEthertype(action, outBuffer);
230 private static void encodePopVlanAction(ByteBuf outBuffer) {
231 outBuffer.writeShort(POP_VLAN_CODE);
232 encodeRestOfActionHeader(outBuffer);
235 private static void encodePushMplsAction(Action action, ByteBuf outBuffer) {
236 outBuffer.writeShort(PUSH_MPLS_CODE);
237 encodeCommonEthertype(action, outBuffer);
240 private static void encodePopMplsAction(Action action, ByteBuf outBuffer) {
241 outBuffer.writeShort(POP_MPLS_CODE);
242 encodeCommonEthertype(action, outBuffer);
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());
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());
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);
267 private static void encodeDecNwTtlAction(ByteBuf outBuffer) {
268 outBuffer.writeShort(DEC_NW_TTL_CODE);
269 encodeRestOfActionHeader(outBuffer);
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;
280 outBuffer.writeShort(length);
281 MatchSerializer.encodeMatchEntries(oxmField.getMatchEntries(), outBuffer);
282 if (paddingRemainder != 0) {
283 ByteBufUtils.padBuffer(EncodeConstants.PADDING - paddingRemainder, outBuffer);
287 private static void encodePushPbbAction(Action action, ByteBuf outBuffer) {
288 outBuffer.writeShort(PUSH_PBB_CODE);
289 encodeCommonEthertype(action, outBuffer);
292 private static void encodePopPbbAction(ByteBuf outBuffer) {
293 outBuffer.writeShort(POP_PBB_CODE);
294 encodeRestOfActionHeader(outBuffer);
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());
304 private static void encodeRestOfActionHeader(ByteBuf outBuffer) {
305 outBuffer.writeShort(ACTION_HEADER_LENGTH);
306 ByteBufUtils.padBuffer(PADDING_IN_ACTION_HEADER, outBuffer);
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);
317 * Computes length of actions
318 * @param actionsList list of actions
319 * @return actions length
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;
337 lengthOfActions += LENGTH_OF_OTHER_ACTIONS;
341 return lengthOfActions;