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 org.opendaylight.openflowjava.protocol.api.extensibility.HeaderSerializer;
14 import org.opendaylight.openflowjava.protocol.api.extensibility.MessageTypeKey;
15 import org.opendaylight.openflowjava.protocol.api.extensibility.OFSerializer;
16 import org.opendaylight.openflowjava.protocol.api.extensibility.RegistryInjector;
17 import org.opendaylight.openflowjava.protocol.api.extensibility.SerializerRegistry;
18 import org.opendaylight.openflowjava.protocol.impl.deserialization.EnhancedMessageTypeKey;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.EthertypeAction;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ExperimenterAction;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.GroupIdAction;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MaxLengthAction;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MplsTtlAction;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.NwTtlAction;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.OxmFieldsAction;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PortAction;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.QueueIdAction;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.CopyTtlIn;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.CopyTtlOut;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.DecMplsTtl;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.DecNwTtl;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.Experimenter;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.Group;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.Output;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.PopMpls;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.PopPbb;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.PopVlan;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.PushMpls;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.PushPbb;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.PushVlan;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.SetField;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.SetMplsTtl;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.SetNwTtl;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.SetQueue;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.action.rev130731.actions.grouping.Action;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.oxm.fields.grouping.MatchEntries;
49 * Serializes ofp_actions (OpenFlow v1.3)
50 * @author michal.polkorab
51 * @author timotej.kubas
53 public class OF13ActionsSerializer implements OFSerializer<Action>,
54 HeaderSerializer<Action>, RegistryInjector {
56 private static final byte OUTPUT_CODE = 0;
57 private static final byte COPY_TTL_OUT_CODE = 11;
58 private static final byte COPY_TTL_IN_CODE = 12;
59 private static final byte SET_MPLS_TTL_CODE = 15;
60 private static final byte DEC_MPLS_TTL_CODE = 16;
61 private static final byte PUSH_VLAN_CODE = 17;
62 private static final byte POP_VLAN_CODE = 18;
63 private static final byte PUSH_MPLS_CODE = 19;
64 private static final byte POP_MPLS_CODE = 20;
65 private static final byte SET_QUEUE_CODE = 21;
66 private static final byte GROUP_CODE = 22;
67 private static final byte SET_NW_TTL_CODE = 23;
68 private static final byte DEC_NW_TTL_CODE = 24;
69 private static final int SET_FIELD_CODE = 25;
70 private static final byte PUSH_PBB_CODE = 26;
71 private static final byte POP_PBB_CODE = 27;
72 private static final byte OUTPUT_LENGTH = 16;
73 private static final byte SET_MPLS_TTL_LENGTH = 8;
74 private static final byte SET_QUEUE_LENGTH = 8;
75 private static final byte GROUP_LENGTH = 8;
76 private static final byte SET_NW_TTL_LENGTH = 8;
77 private static final byte ACTION_HEADER_LENGTH = 8;
78 private static final byte LENGTH_OF_ETHERTYPE_ACTION = 8;
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 private SerializerRegistry registry;
88 public void serialize(Action action, ByteBuf outBuffer) {
89 if (action.getType().isAssignableFrom(Output.class)) {
90 encodeOutputAction(action, outBuffer);
91 } else if (action.getType().isAssignableFrom(CopyTtlOut.class)) {
92 encodeCopyTtlOutAction(outBuffer);
93 } else if (action.getType().isAssignableFrom(CopyTtlIn.class)) {
94 encodeCopyTtlInAction(outBuffer);
95 } else if (action.getType().isAssignableFrom(SetMplsTtl.class)) {
96 encodeSetMplsTtltAction(action, outBuffer);
97 } else if (action.getType().isAssignableFrom(DecMplsTtl.class)) {
98 encodeDecMplsTtlAction(outBuffer);
99 } else if (action.getType().isAssignableFrom(PushVlan.class)) {
100 encodePushVlanAction(action, outBuffer);
101 } else if (action.getType().isAssignableFrom(PopVlan.class)) {
102 encodePopVlanAction(outBuffer);
103 } else if (action.getType().isAssignableFrom(PushMpls.class)) {
104 encodePushMplsAction(action, outBuffer);
105 } else if (action.getType().isAssignableFrom(PopMpls.class)) {
106 encodePopMplsAction(action, outBuffer);
107 } else if (action.getType().isAssignableFrom(SetQueue.class)) {
108 encodeSetQueueAction(action, outBuffer);
109 } else if (action.getType().isAssignableFrom(Group.class)) {
110 encodeGroupAction(action, outBuffer);
111 } else if (action.getType().isAssignableFrom(SetNwTtl.class)) {
112 encodeSetNwTtlAction(action, outBuffer);
113 } else if (action.getType().isAssignableFrom(DecNwTtl.class)) {
114 encodeDecNwTtlAction(outBuffer);
115 } else if (action.getType().isAssignableFrom(SetField.class)) {
116 encodeSetFieldAction(action, outBuffer);
117 } else if (action.getType().isAssignableFrom(PushPbb.class)) {
118 encodePushPbbAction(action, outBuffer);
119 } else if (action.getType().isAssignableFrom(PopPbb.class)) {
120 encodePopPbbAction(outBuffer);
121 } else if (action.getType().isAssignableFrom(Experimenter.class)) {
122 encodeExperimenterAction(action, outBuffer);
126 private static void writeTypeAndLength(ByteBuf out, int type, int length) {
127 out.writeShort(type);
128 out.writeShort(length);
131 private static void encodeOutputAction(Action action, ByteBuf outBuffer) {
132 outBuffer.writeShort(OUTPUT_CODE);
133 outBuffer.writeShort(OUTPUT_LENGTH);
134 PortAction port = action.getAugmentation(PortAction.class);
135 outBuffer.writeInt(port.getPort().getValue().intValue());
136 MaxLengthAction maxlength = action.getAugmentation(MaxLengthAction.class);
137 outBuffer.writeShort(maxlength.getMaxLength());
138 ByteBufUtils.padBuffer(OUTPUT_PADDING, outBuffer);
141 private static void encodeCopyTtlOutAction(ByteBuf outBuffer) {
142 outBuffer.writeShort(COPY_TTL_OUT_CODE);
143 encodeRestOfActionHeader(outBuffer);
146 private static void encodeCopyTtlInAction(ByteBuf outBuffer) {
147 outBuffer.writeShort(COPY_TTL_IN_CODE);
148 encodeRestOfActionHeader(outBuffer);
151 private static void encodeSetMplsTtltAction(Action action, ByteBuf outBuffer) {
152 outBuffer.writeShort(SET_MPLS_TTL_CODE);
153 outBuffer.writeShort(SET_MPLS_TTL_LENGTH);
154 MplsTtlAction mplsTtl = action.getAugmentation(MplsTtlAction.class);
155 outBuffer.writeByte(mplsTtl.getMplsTtl());
156 ByteBufUtils.padBuffer(SET_MPLS_TTL_PADDING, outBuffer);
159 private static void encodeDecMplsTtlAction(ByteBuf outBuffer) {
160 outBuffer.writeShort(DEC_MPLS_TTL_CODE);
161 encodeRestOfActionHeader(outBuffer);
164 private static void encodePushVlanAction(Action action, ByteBuf outBuffer) {
165 outBuffer.writeShort(PUSH_VLAN_CODE);
166 encodeCommonEthertype(action, outBuffer);
169 private static void encodePopVlanAction(ByteBuf outBuffer) {
170 outBuffer.writeShort(POP_VLAN_CODE);
171 encodeRestOfActionHeader(outBuffer);
174 private static void encodePushMplsAction(Action action, ByteBuf outBuffer) {
175 outBuffer.writeShort(PUSH_MPLS_CODE);
176 encodeCommonEthertype(action, outBuffer);
179 private static void encodePopMplsAction(Action action, ByteBuf outBuffer) {
180 outBuffer.writeShort(POP_MPLS_CODE);
181 encodeCommonEthertype(action, outBuffer);
184 private static void encodeSetQueueAction(Action action, ByteBuf outBuffer) {
185 outBuffer.writeShort(SET_QUEUE_CODE);
186 outBuffer.writeShort(SET_QUEUE_LENGTH);
187 QueueIdAction queueId = action.getAugmentation(QueueIdAction.class);
188 outBuffer.writeInt(queueId.getQueueId().intValue());
191 private static void encodeGroupAction(Action action, ByteBuf outBuffer) {
192 outBuffer.writeShort(GROUP_CODE);
193 outBuffer.writeShort(GROUP_LENGTH);
194 GroupIdAction groupId = action.getAugmentation(GroupIdAction.class);
195 outBuffer.writeInt(groupId.getGroupId().intValue());
198 private static void encodeSetNwTtlAction(Action action, ByteBuf outBuffer) {
199 outBuffer.writeShort(SET_NW_TTL_CODE);
200 outBuffer.writeShort(SET_NW_TTL_LENGTH);
201 NwTtlAction nwTtl = action.getAugmentation(NwTtlAction.class);
202 outBuffer.writeByte(nwTtl.getNwTtl());
203 ByteBufUtils.padBuffer(SET_NW_TTL_PADDING, outBuffer);
206 private static void encodeDecNwTtlAction(ByteBuf outBuffer) {
207 outBuffer.writeShort(DEC_NW_TTL_CODE);
208 encodeRestOfActionHeader(outBuffer);
211 private void encodeSetFieldAction(Action action, ByteBuf outBuffer) {
212 OxmFieldsAction oxmField = action.getAugmentation(OxmFieldsAction.class);
213 int setFieldStartIndex = outBuffer.writerIndex();
214 outBuffer.writeShort(SET_FIELD_CODE);
215 int setFieldLengthIndex = outBuffer.writerIndex();
216 outBuffer.writeShort(EncodeConstants.EMPTY_LENGTH);
217 MatchEntries entry = oxmField.getMatchEntries().get(0);
218 OFSerializer<MatchEntries> serializer = registry.getSerializer(new EnhancedMessageTypeKey<>(
219 EncodeConstants.OF13_VERSION_ID, entry.getOxmClass(), entry.getOxmMatchField()));
220 serializer.serialize(entry, outBuffer);
221 int paddingRemainder = (outBuffer.writerIndex() - setFieldStartIndex) % EncodeConstants.PADDING;
222 if (paddingRemainder != 0) {
223 ByteBufUtils.padBuffer(EncodeConstants.PADDING - paddingRemainder, outBuffer);
225 outBuffer.setShort(setFieldLengthIndex, outBuffer.writerIndex() - setFieldStartIndex);
228 private static void encodePushPbbAction(Action action, ByteBuf outBuffer) {
229 outBuffer.writeShort(PUSH_PBB_CODE);
230 encodeCommonEthertype(action, outBuffer);
233 private static void encodePopPbbAction(ByteBuf outBuffer) {
234 outBuffer.writeShort(POP_PBB_CODE);
235 encodeRestOfActionHeader(outBuffer);
238 private void encodeExperimenterAction(Action action, ByteBuf outBuffer) {
239 OFSerializer<ExperimenterAction> serializer = registry.getSerializer(
240 new MessageTypeKey<>(EncodeConstants.OF13_VERSION_ID, Experimenter.class));
241 serializer.serialize((ExperimenterAction) action, outBuffer);
244 private static void encodeRestOfActionHeader(ByteBuf outBuffer) {
245 outBuffer.writeShort(ACTION_HEADER_LENGTH);
246 ByteBufUtils.padBuffer(PADDING_IN_ACTION_HEADER, outBuffer);
249 private static void encodeCommonEthertype(Action action, ByteBuf outBuffer) {
250 EthertypeAction ethertype = action.getAugmentation(EthertypeAction.class);
251 outBuffer.writeShort(LENGTH_OF_ETHERTYPE_ACTION);
252 outBuffer.writeShort(ethertype.getEthertype().getValue());
253 ByteBufUtils.padBuffer(ETHERTYPE_ACTION_PADDING, outBuffer);
257 public void injectSerializerRegistry(SerializerRegistry serializerRegistry) {
258 this.registry = serializerRegistry;
262 public void serializeHeader(Action action, ByteBuf outBuffer) {
263 if (action.getType().isAssignableFrom(Output.class)) {
264 writeTypeAndLength(outBuffer, OUTPUT_CODE, ACTION_IDS_LENGTH);
265 } else if (action.getType().isAssignableFrom(CopyTtlOut.class)) {
266 writeTypeAndLength(outBuffer, COPY_TTL_OUT_CODE, ACTION_IDS_LENGTH);
267 } else if (action.getType().isAssignableFrom(CopyTtlIn.class)) {
268 writeTypeAndLength(outBuffer, COPY_TTL_IN_CODE, ACTION_IDS_LENGTH);
269 } else if (action.getType().isAssignableFrom(SetMplsTtl.class)) {
270 writeTypeAndLength(outBuffer, SET_MPLS_TTL_CODE, ACTION_IDS_LENGTH);
271 } else if (action.getType().isAssignableFrom(DecMplsTtl.class)) {
272 writeTypeAndLength(outBuffer, DEC_MPLS_TTL_CODE, ACTION_IDS_LENGTH);
273 } else if (action.getType().isAssignableFrom(PushVlan.class)) {
274 writeTypeAndLength(outBuffer, PUSH_VLAN_CODE, ACTION_IDS_LENGTH);
275 } else if (action.getType().isAssignableFrom(PopVlan.class)) {
276 writeTypeAndLength(outBuffer, POP_VLAN_CODE, ACTION_IDS_LENGTH);
277 } else if (action.getType().isAssignableFrom(PushMpls.class)) {
278 writeTypeAndLength(outBuffer, PUSH_MPLS_CODE, ACTION_IDS_LENGTH);
279 } else if (action.getType().isAssignableFrom(PopMpls.class)) {
280 writeTypeAndLength(outBuffer, POP_MPLS_CODE, ACTION_IDS_LENGTH);
281 } else if (action.getType().isAssignableFrom(SetQueue.class)) {
282 writeTypeAndLength(outBuffer, SET_QUEUE_CODE, ACTION_IDS_LENGTH);
283 } else if (action.getType().isAssignableFrom(Group.class)) {
284 writeTypeAndLength(outBuffer, GROUP_CODE, ACTION_IDS_LENGTH);
285 } else if (action.getType().isAssignableFrom(SetNwTtl.class)) {
286 writeTypeAndLength(outBuffer, SET_NW_TTL_CODE, ACTION_IDS_LENGTH);
287 } else if (action.getType().isAssignableFrom(DecNwTtl.class)) {
288 writeTypeAndLength(outBuffer, DEC_NW_TTL_CODE, ACTION_IDS_LENGTH);
289 } else if (action.getType().isAssignableFrom(SetField.class)) {
290 writeTypeAndLength(outBuffer, SET_FIELD_CODE, ACTION_IDS_LENGTH);
291 } else if (action.getType().isAssignableFrom(PushPbb.class)) {
292 writeTypeAndLength(outBuffer, PUSH_PBB_CODE, ACTION_IDS_LENGTH);
293 } else if (action.getType().isAssignableFrom(PopPbb.class)) {
294 writeTypeAndLength(outBuffer, POP_PBB_CODE, ACTION_IDS_LENGTH);
295 } else if (action.getType().isAssignableFrom(Experimenter.class)) {
296 HeaderSerializer<ExperimenterAction> serializer = registry.getSerializer(
297 new MessageTypeKey<>(EncodeConstants.OF13_VERSION_ID, Experimenter.class));
298 serializer.serializeHeader((ExperimenterAction) action, outBuffer);