Match and actions (de)serialization + fix
[openflowjava.git] / openflow-protocol-impl / src / main / java / org / opendaylight / openflowjava / protocol / impl / util / MatchSerializer.java
1 /* Copyright (C)2013 Pantheon Technologies, s.r.o. All rights reserved. */\r
2 package org.opendaylight.openflowjava.protocol.impl.util;\r
3 \r
4 import io.netty.buffer.ByteBuf;\r
5 \r
6 import java.util.List;\r
7 \r
8 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.BosMatchEntry;\r
9 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.EthTypeMatchEntry;\r
10 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv4CodeMatchEntry;\r
11 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv4TypeMatchEntry;\r
12 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv6CodeMatchEntry;\r
13 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv6TypeMatchEntry;\r
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MacAddressMatchEntry;\r
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MaskMatchEntry;\r
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MetadataMatchEntry;\r
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MplsLabelMatchEntry;\r
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.OpCodeMatchEntry;\r
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PortMatchEntry;\r
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PortNumberMatchEntry;\r
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.TcMatchEntry;\r
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.VlanPcpMatchEntry;\r
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.VlanVidMatchEntry;\r
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.StandardMatchType;\r
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpOp;\r
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpSha;\r
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpSpa;\r
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpTha;\r
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpTpa;\r
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Clazz;\r
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.EthDst;\r
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.EthSrc;\r
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.EthType;\r
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ExperimenterClass;\r
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv4Code;\r
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv4Type;\r
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv6Code;\r
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv6Type;\r
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.InPhyPort;\r
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.InPort;\r
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.IpDscp;\r
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.IpEcn;\r
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.IpProto;\r
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv4Dst;\r
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv4Src;\r
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Dst;\r
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Exthdr;\r
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Flabel;\r
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6NdSll;\r
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6NdTarget;\r
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6NdTll;\r
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Src;\r
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MatchField;\r
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Metadata;\r
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MplsBos;\r
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MplsLabel;\r
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MplsTc;\r
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Nxm0Class;\r
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Nxm1Class;\r
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.OpenflowBasicClass;\r
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.OxmMatchType;\r
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.PbbIsid;\r
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.SctpDst;\r
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.SctpSrc;\r
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.TcpDst;\r
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.TcpSrc;\r
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.TunnelId;\r
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.UdpDst;\r
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.UdpSrc;\r
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.VlanPcp;\r
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.VlanVid;\r
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.oxm.fields.MatchEntries;\r
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.flow.mod.Match;\r
74 import org.slf4j.Logger;\r
75 import org.slf4j.LoggerFactory;\r
76 \r
77 /**\r
78  * @author michal.polkorab\r
79  *\r
80  */\r
81 public class MatchSerializer {\r
82     \r
83     private static final Logger LOGGER = LoggerFactory.getLogger(MatchSerializer.class);\r
84 \r
85     /**\r
86      * Encodes OF match\r
87      * @param match ofp_match object\r
88      * @param out output ByteBuf\r
89      */\r
90     public static void encodeMatch(Match match, ByteBuf out) {\r
91         final byte PADDING_IN_OFP_MATCH = 4;\r
92         encodeType(match, out);\r
93         //TODO - compute length\r
94         encodeMatchEntries(match.getMatchEntries(), out);\r
95         ByteBufUtils.padBuffer(PADDING_IN_OFP_MATCH, out);\r
96         \r
97     }\r
98 \r
99     private static void encodeType(Match match, ByteBuf out) {\r
100         final byte STANDARD_MATCH_TYPE_CODE = 0;\r
101         final byte OXM_MATCH_TYPE_CODE = 1;\r
102         if (match.getType().equals(StandardMatchType.class)) {\r
103             out.writeShort(STANDARD_MATCH_TYPE_CODE);\r
104         } else if (match.getType().equals(OxmMatchType.class)) {\r
105             out.writeShort(OXM_MATCH_TYPE_CODE);\r
106         }\r
107     }\r
108 \r
109     private static void encodeMatchEntries(List<MatchEntries> matchEntries, ByteBuf out) {\r
110         if (matchEntries == null) {\r
111             LOGGER.warn("Match entry is null");\r
112             return;\r
113         }\r
114         for (MatchEntries entry : matchEntries) {\r
115             encodeClass(entry.getOxmClass(), out);\r
116             encodeRest(entry, null);\r
117         }\r
118     }\r
119 \r
120     private static void encodeClass(Class<? extends Clazz> clazz, ByteBuf out) {\r
121         final int NXM0_CLASS_CODE = 0x0000;\r
122         final int NXM1_CLASS_CODE = 0x0001;\r
123         final int OPENFLOW_BASIC_CLASS_CODE = 0x8000;\r
124         final int EXPERIMENTER_CLASS_CODE = 0xFFFF;\r
125         if (Nxm0Class.class.equals(clazz)) {\r
126             out.writeShort(NXM0_CLASS_CODE);\r
127         } else if (Nxm1Class.class.equals(clazz)) {\r
128             out.writeShort(NXM1_CLASS_CODE);\r
129         } else if (OpenflowBasicClass.class.equals(clazz)) {\r
130             out.writeShort(OPENFLOW_BASIC_CLASS_CODE);\r
131         } else if (ExperimenterClass.class.equals(clazz)) {\r
132             out.writeShort(EXPERIMENTER_CLASS_CODE);\r
133         }\r
134     }\r
135     \r
136     private static void encodeRest(MatchEntries entry, ByteBuf out) {\r
137         int fieldValue = 0;\r
138         Class<? extends MatchField> field = entry.getOxmMatchField();\r
139         if (field.equals(InPort.class)) {\r
140             fieldValue = 0;\r
141             writeOxmFieldAndLength(out, fieldValue, Integer.SIZE / Byte.SIZE);\r
142             out.writeInt(entry.getAugmentation(PortNumberMatchEntry.class).getPortNumber().getValue().intValue());\r
143         } else if (field.equals(InPhyPort.class)) {\r
144             fieldValue = 1;\r
145             writeOxmFieldAndLength(out, fieldValue, Integer.SIZE / Byte.SIZE);\r
146             out.writeInt(entry.getAugmentation(PortNumberMatchEntry.class).getPortNumber().getValue().intValue());\r
147         } else if (field.equals(Metadata.class)) {\r
148             fieldValue = 2;\r
149             fieldValue = fieldValue << 1;\r
150             if (entry.isHasMask()) {\r
151                 fieldValue = fieldValue | 1;\r
152                 out.writeByte(fieldValue);\r
153                 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
154                 out.writeByte(Long.SIZE / Byte.SIZE + mask.length);\r
155                 out.writeBytes(entry.getAugmentation(MetadataMatchEntry.class).getMetadata());\r
156                 out.writeBytes(mask);\r
157             } else {\r
158                 out.writeByte(fieldValue);\r
159                 out.writeByte(Long.SIZE / Byte.SIZE);\r
160                 out.writeBytes(entry.getAugmentation(MetadataMatchEntry.class).getMetadata());\r
161             }\r
162         } else if (field.equals(EthDst.class)) {\r
163             fieldValue = 3;\r
164             fieldValue = fieldValue << 1;\r
165             if (entry.isHasMask()) {\r
166                 fieldValue = fieldValue | 1;\r
167                 out.writeByte(fieldValue);\r
168                 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
169                 out.writeByte((Integer.SIZE + Short.SIZE) / Byte.SIZE + mask.length);\r
170                 out.writeBytes(entry.getAugmentation(MacAddressMatchEntry.class).getMacAddress().getValue().getBytes());\r
171                 out.writeBytes(entry.getAugmentation(MaskMatchEntry.class).getMask());\r
172             } else {\r
173                 out.writeByte(fieldValue);\r
174                 out.writeByte(Long.SIZE / Byte.SIZE);\r
175                 out.writeBytes(entry.getAugmentation(MacAddressMatchEntry.class).getMacAddress().getValue().getBytes());\r
176             }\r
177         } else if (field.equals(EthSrc.class)) {\r
178             fieldValue = 4;\r
179             fieldValue = fieldValue << 1;\r
180             if (entry.isHasMask()) {\r
181                 fieldValue = fieldValue | 1;\r
182                 out.writeByte(fieldValue);\r
183                 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
184                 out.writeByte(Long.SIZE / Byte.SIZE + mask.length);\r
185                 out.writeBytes(entry.getAugmentation(MacAddressMatchEntry.class).getMacAddress().getValue().getBytes());\r
186                 out.writeBytes(mask);\r
187             } else {\r
188                 out.writeByte(fieldValue);\r
189                 out.writeByte(Long.SIZE / Byte.SIZE);\r
190                 out.writeBytes(entry.getAugmentation(MacAddressMatchEntry.class).getMacAddress().getValue().getBytes());\r
191             }\r
192         } else if (field.equals(EthType.class)) {\r
193             fieldValue = 5;\r
194             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
195             out.writeShort(entry.getAugmentation(EthTypeMatchEntry.class).getEthType().getValue().shortValue());\r
196         } else if (field.equals(VlanVid.class)) {\r
197             fieldValue = 6;\r
198             fieldValue = fieldValue << 1;\r
199             if (entry.isHasMask()) {\r
200                 fieldValue = fieldValue | 1;\r
201                 out.writeByte(fieldValue);\r
202                 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
203                 out.writeByte(Short.SIZE / Byte.SIZE + mask.length);\r
204                 out.writeShort(entry.getAugmentation(VlanVidMatchEntry.class).getVlanVid());\r
205                 out.writeBytes(mask);\r
206             } else {\r
207                 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
208                 out.writeShort(entry.getAugmentation(VlanVidMatchEntry.class).getVlanVid());\r
209             }\r
210         } else if (field.equals(VlanPcp.class)) {\r
211             fieldValue = 7;\r
212             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
213             out.writeByte(entry.getAugmentation(VlanPcpMatchEntry.class).getVlanPcp().byteValue());\r
214         } else if (field.equals(IpDscp.class)) {\r
215             fieldValue = 8;\r
216         } else if (field.equals(IpEcn.class)) {\r
217             fieldValue = 9;\r
218         } else if (field.equals(IpProto.class)) {\r
219             fieldValue = 10;\r
220         } else if (field.equals(Ipv4Src.class)) {\r
221             fieldValue = 11;\r
222         } else if (field.equals(Ipv4Dst.class)) {\r
223             fieldValue = 12;\r
224         } else if (field.equals(TcpSrc.class)) {\r
225             fieldValue = 13;\r
226             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
227             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
228         } else if (field.equals(TcpDst.class)) {\r
229             fieldValue = 14;\r
230             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
231             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
232         } else if (field.equals(UdpSrc.class)) {\r
233             fieldValue = 15;\r
234             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
235             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
236         } else if (field.equals(UdpDst.class)) {\r
237             fieldValue = 16;\r
238             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
239             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
240         } else if (field.equals(SctpSrc.class)) {\r
241             fieldValue = 17;\r
242             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
243             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
244         } else if (field.equals(SctpDst.class)) {\r
245             fieldValue = 18;\r
246             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
247             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
248         } else if (field.equals(Icmpv4Type.class)) {\r
249             fieldValue = 19;\r
250             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
251             out.writeByte(entry.getAugmentation(Icmpv4TypeMatchEntry.class).getIcmpv4Type());\r
252         } else if (field.equals(Icmpv4Code.class)) {\r
253             fieldValue = 20;\r
254             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
255             out.writeByte(entry.getAugmentation(Icmpv4CodeMatchEntry.class).getIcmpv4Code());\r
256         } else if (field.equals(ArpOp.class)) {\r
257             fieldValue = 21;\r
258             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
259             out.writeShort(entry.getAugmentation(OpCodeMatchEntry.class).getOpCode());\r
260         } else if (field.equals(ArpSpa.class)) {\r
261             fieldValue = 22;\r
262         } else if (field.equals(ArpTpa.class)) {\r
263             fieldValue = 23;\r
264         } else if (field.equals(ArpSha.class)) {\r
265             fieldValue = 24;\r
266         } else if (field.equals(ArpTha.class)) {\r
267             fieldValue = 25;\r
268         } else if (field.equals(Ipv6Src.class)) {\r
269             fieldValue = 26;\r
270         } else if (field.equals(Ipv6Dst.class)) {\r
271             fieldValue = 27;\r
272         } else if (field.equals(Ipv6Flabel.class)) {\r
273             fieldValue = 28;\r
274         } else if (field.equals(Icmpv6Type.class)) {\r
275             fieldValue = 29;\r
276             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
277             out.writeByte(entry.getAugmentation(Icmpv6TypeMatchEntry.class).getIcmpv6Type());\r
278         } else if (field.equals(Icmpv6Code.class)) {\r
279             fieldValue = 30;\r
280             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
281             out.writeByte(entry.getAugmentation(Icmpv6CodeMatchEntry.class).getIcmpv6Code());\r
282         } else if (field.equals(Ipv6NdTarget.class)) {\r
283             fieldValue = 31;\r
284         } else if (field.equals(Ipv6NdSll.class)) {\r
285             fieldValue = 32;\r
286         } else if (field.equals(Ipv6NdTll.class)) {\r
287             fieldValue = 33;\r
288         } else if (field.equals(MplsLabel.class)) {\r
289             fieldValue = 34;\r
290             writeOxmFieldAndLength(out, fieldValue, Integer.SIZE / Byte.SIZE);\r
291             out.writeInt(entry.getAugmentation(MplsLabelMatchEntry.class).getMplsLabel().intValue());\r
292         } else if (field.equals(MplsTc.class)) {\r
293             fieldValue = 35;\r
294             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
295             out.writeByte(entry.getAugmentation(TcMatchEntry.class).getTc());\r
296         } else if (field.equals(MplsBos.class)) {\r
297             fieldValue = 36;\r
298             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
299             out.writeBoolean(entry.getAugmentation(BosMatchEntry.class).isBos().booleanValue());\r
300         } else if (field.equals(PbbIsid.class)) {\r
301             fieldValue = 37;\r
302         } else if (field.equals(TunnelId.class)) {\r
303             fieldValue = 38;\r
304         } else if (field.equals(Ipv6Exthdr.class)) {\r
305             fieldValue = 39;\r
306         }\r
307     }\r
308 \r
309     private static void writeOxmFieldAndLength(ByteBuf out, int fieldValue, int length) {\r
310         int fieldAndMask = fieldValue << 1;\r
311         out.writeByte(fieldAndMask);\r
312         out.writeByte(length);\r
313     }\r
314     \r
315 }\r