Extensibility support (serialization part)
[openflowjava.git] / openflow-protocol-impl / src / main / java / org / opendaylight / openflowjava / protocol / impl / util / OF13ActionsSerializer.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 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;
47
48 /**
49  * Serializes ofp_actions (OpenFlow v1.3)
50  * @author michal.polkorab
51  * @author timotej.kubas
52  */
53 public class OF13ActionsSerializer implements OFSerializer<Action>,
54         HeaderSerializer<Action>, RegistryInjector {
55
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;
86
87     @Override
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);
123         }
124     }
125
126     private static void writeTypeAndLength(ByteBuf out, int type, int length) {
127         out.writeShort(type);
128         out.writeShort(length);
129     }
130
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);
139     }
140
141     private static void encodeCopyTtlOutAction(ByteBuf outBuffer) {
142         outBuffer.writeShort(COPY_TTL_OUT_CODE);
143         encodeRestOfActionHeader(outBuffer);
144     }
145     
146     private static void encodeCopyTtlInAction(ByteBuf outBuffer) {
147         outBuffer.writeShort(COPY_TTL_IN_CODE);
148         encodeRestOfActionHeader(outBuffer);
149     }
150     
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);
157     }
158     
159     private static void encodeDecMplsTtlAction(ByteBuf outBuffer) {
160         outBuffer.writeShort(DEC_MPLS_TTL_CODE);
161         encodeRestOfActionHeader(outBuffer);
162     }
163     
164     private static void encodePushVlanAction(Action action, ByteBuf outBuffer) {
165         outBuffer.writeShort(PUSH_VLAN_CODE);
166         encodeCommonEthertype(action, outBuffer);
167     }
168
169     private static void encodePopVlanAction(ByteBuf outBuffer) {
170         outBuffer.writeShort(POP_VLAN_CODE);
171         encodeRestOfActionHeader(outBuffer);
172     }
173     
174     private static void encodePushMplsAction(Action action, ByteBuf outBuffer) {
175         outBuffer.writeShort(PUSH_MPLS_CODE);
176         encodeCommonEthertype(action, outBuffer);
177     }
178     
179     private static void encodePopMplsAction(Action action, ByteBuf outBuffer) {
180         outBuffer.writeShort(POP_MPLS_CODE);
181         encodeCommonEthertype(action, outBuffer);
182     }
183     
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());
189     }
190
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());
196     }
197     
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);
204     }
205     
206     private static void encodeDecNwTtlAction(ByteBuf outBuffer) {
207         outBuffer.writeShort(DEC_NW_TTL_CODE);
208         encodeRestOfActionHeader(outBuffer);
209     }
210
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);
224         }
225         outBuffer.setShort(setFieldLengthIndex, outBuffer.writerIndex() - setFieldStartIndex);
226     }
227     
228     private static void encodePushPbbAction(Action action, ByteBuf outBuffer) {
229         outBuffer.writeShort(PUSH_PBB_CODE);
230         encodeCommonEthertype(action, outBuffer);
231     }
232     
233     private static void encodePopPbbAction(ByteBuf outBuffer) {
234         outBuffer.writeShort(POP_PBB_CODE);
235         encodeRestOfActionHeader(outBuffer);
236     }
237
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);
242     }
243     
244     private static void encodeRestOfActionHeader(ByteBuf outBuffer) {
245         outBuffer.writeShort(ACTION_HEADER_LENGTH);
246         ByteBufUtils.padBuffer(PADDING_IN_ACTION_HEADER, outBuffer);
247     }
248     
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);
254     }
255
256     @Override
257     public void injectSerializerRegistry(SerializerRegistry serializerRegistry) {
258         this.registry = serializerRegistry;
259     }
260
261     @Override
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);
299         }
300     }
301
302 }