Quickfix - fixed missing output ByteBuf in MatchSerializer
[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.Arrays;\r
7 import java.util.HashMap;\r
8 import java.util.List;\r
9 import java.util.Map;\r
10 \r
11 import org.opendaylight.openflowjava.protocol.impl.serialization.factories.EncodeConstants;\r
12 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.BosMatchEntry;\r
13 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.DscpMatchEntry;\r
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.EcnMatchEntry;\r
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.EthTypeMatchEntry;\r
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv4CodeMatchEntry;\r
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv4TypeMatchEntry;\r
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv6CodeMatchEntry;\r
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv6TypeMatchEntry;\r
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Ipv4AddressMatchEntry;\r
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Ipv6AddressMatchEntry;\r
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Ipv6FlabelMatchEntry;\r
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.IsidMatchEntry;\r
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MacAddressMatchEntry;\r
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MaskMatchEntry;\r
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MetadataMatchEntry;\r
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MplsLabelMatchEntry;\r
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.OpCodeMatchEntry;\r
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PortMatchEntry;\r
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PortNumberMatchEntry;\r
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ProtocolNumberMatchEntry;\r
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PseudoFieldMatchEntry;\r
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PseudoFieldMatchEntry.PseudoField;\r
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.TcMatchEntry;\r
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.VlanPcpMatchEntry;\r
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.VlanVidMatchEntry;\r
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.StandardMatchType;\r
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpOp;\r
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpSha;\r
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpSpa;\r
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpTha;\r
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpTpa;\r
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Clazz;\r
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.EthDst;\r
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.EthSrc;\r
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.EthType;\r
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ExperimenterClass;\r
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv4Code;\r
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv4Type;\r
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv6Code;\r
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv6Type;\r
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.InPhyPort;\r
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.InPort;\r
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.IpDscp;\r
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.IpEcn;\r
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.IpProto;\r
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv4Dst;\r
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv4Src;\r
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Dst;\r
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Exthdr;\r
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Flabel;\r
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6NdSll;\r
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6NdTarget;\r
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6NdTll;\r
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Src;\r
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MatchField;\r
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Metadata;\r
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MplsBos;\r
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MplsLabel;\r
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MplsTc;\r
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Nxm0Class;\r
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Nxm1Class;\r
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.OpenflowBasicClass;\r
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.OxmMatchType;\r
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.PbbIsid;\r
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.SctpDst;\r
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.SctpSrc;\r
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.TcpDst;\r
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.TcpSrc;\r
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.TunnelId;\r
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.UdpDst;\r
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.UdpSrc;\r
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.VlanPcp;\r
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.VlanVid;\r
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.oxm.fields.MatchEntries;\r
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.match.grouping.Match;\r
87 import org.slf4j.Logger;\r
88 import org.slf4j.LoggerFactory;\r
89 \r
90 /**\r
91  * Serializes ofp_match (OpenFlow v1.3) and its oxm_fields structures\r
92  * @author michal.polkorab\r
93  * @author timotej.kubas\r
94  */\r
95 public class MatchSerializer {\r
96     \r
97     private static final Logger LOGGER = LoggerFactory.getLogger(MatchSerializer.class);\r
98 \r
99     /**\r
100      * Encodes match (OpenFlow v1.3)\r
101      * @param match ofp_match object\r
102      * @param out output ByteBuf\r
103      */\r
104     public static void encodeMatch(Match match, ByteBuf out) {\r
105         if (match == null) {\r
106             LOGGER.debug("Match is null");\r
107             return;\r
108         }\r
109         encodeType(match, out);\r
110         // Length of ofp_match (excluding padding)\r
111         int length = computeMatchLength(match);\r
112         out.writeShort(length);\r
113         encodeMatchEntries(match.getMatchEntries(), out);\r
114         int paddingRemainder = length % EncodeConstants.PADDING;\r
115         if (paddingRemainder != 0) {\r
116             ByteBufUtils.padBuffer(EncodeConstants.PADDING - paddingRemainder, out);\r
117         }\r
118     }\r
119 \r
120     private static void encodeType(Match match, ByteBuf out) {\r
121         final byte STANDARD_MATCH_TYPE_CODE = 0;\r
122         final byte OXM_MATCH_TYPE_CODE = 1;\r
123         if (match.getType().equals(StandardMatchType.class)) {\r
124             out.writeShort(STANDARD_MATCH_TYPE_CODE);\r
125         } else if (match.getType().equals(OxmMatchType.class)) {\r
126             out.writeShort(OXM_MATCH_TYPE_CODE);\r
127         }\r
128     }\r
129 \r
130     /**\r
131      * Encodes MatchEntries\r
132      * @param matchEntries list of match entries (oxm_fields)\r
133      * @param out output ByteBuf\r
134      */\r
135     public static void encodeMatchEntries(List<MatchEntries> matchEntries, ByteBuf out) {\r
136         if (matchEntries == null) {\r
137             LOGGER.warn("Match entries are null");\r
138             return;\r
139         }\r
140         for (MatchEntries entry : matchEntries) {\r
141             encodeClass(entry.getOxmClass(), out);\r
142             encodeRest(entry, out);\r
143         }\r
144     }\r
145 \r
146     private static void encodeClass(Class<? extends Clazz> clazz, ByteBuf out) {\r
147         final int NXM0_CLASS_CODE = 0x0000;\r
148         final int NXM1_CLASS_CODE = 0x0001;\r
149         final int OPENFLOW_BASIC_CLASS_CODE = 0x8000;\r
150         final int EXPERIMENTER_CLASS_CODE = 0xFFFF;\r
151         if (Nxm0Class.class.equals(clazz)) {\r
152             out.writeShort(NXM0_CLASS_CODE);\r
153         } else if (Nxm1Class.class.equals(clazz)) {\r
154             out.writeShort(NXM1_CLASS_CODE);\r
155         } else if (OpenflowBasicClass.class.equals(clazz)) {\r
156             out.writeShort(OPENFLOW_BASIC_CLASS_CODE);\r
157         } else if (ExperimenterClass.class.equals(clazz)) {\r
158             out.writeShort(EXPERIMENTER_CLASS_CODE);\r
159         }\r
160     }\r
161     \r
162     private static void encodeRest(MatchEntries entry, ByteBuf out) {\r
163         int fieldValue = 0;\r
164         Class<? extends MatchField> field = entry.getOxmMatchField();\r
165         if (field.equals(InPort.class)) {\r
166             fieldValue = 0;\r
167             writeOxmFieldAndLength(out, fieldValue, Integer.SIZE / Byte.SIZE);\r
168             out.writeInt(entry.getAugmentation(PortNumberMatchEntry.class).getPortNumber().getValue().intValue());\r
169         } else if (field.equals(InPhyPort.class)) {\r
170             fieldValue = 1;\r
171             writeOxmFieldAndLength(out, fieldValue, Integer.SIZE / Byte.SIZE);\r
172             out.writeInt(entry.getAugmentation(PortNumberMatchEntry.class).getPortNumber().getValue().intValue());\r
173         } else if (field.equals(Metadata.class)) {\r
174             fieldValue = 2;\r
175             writeMetadataRelatedEntry(entry, out, fieldValue);\r
176         } else if (field.equals(EthDst.class)) {\r
177             fieldValue = 3;\r
178             writeMacAddressRelatedEntry(entry, out, fieldValue);\r
179         } else if (field.equals(EthSrc.class)) {\r
180             fieldValue = 4;\r
181             writeMacAddressRelatedEntry(entry, out, fieldValue);\r
182         } else if (field.equals(EthType.class)) {\r
183             fieldValue = 5;\r
184             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
185             out.writeShort(entry.getAugmentation(EthTypeMatchEntry.class).getEthType().getValue().shortValue());\r
186         } else if (field.equals(VlanVid.class)) {\r
187             fieldValue = 6;\r
188             fieldValue = fieldValue << 1;\r
189             VlanVidMatchEntry vlanVid = entry.getAugmentation(VlanVidMatchEntry.class);\r
190             int vlanVidValue = vlanVid.getVlanVid() << 1;\r
191             if (vlanVid.isCfiBit()) {\r
192                 vlanVidValue = vlanVidValue | 1;\r
193             }\r
194             if (entry.isHasMask()) {\r
195                 fieldValue = fieldValue | 1;\r
196                 out.writeByte(fieldValue);\r
197                 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
198                 out.writeByte(Short.SIZE / Byte.SIZE + mask.length);\r
199                 out.writeShort(vlanVidValue);\r
200                 out.writeBytes(mask);\r
201             } else {\r
202                 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
203                 out.writeShort(vlanVidValue);\r
204             }\r
205         } else if (field.equals(VlanPcp.class)) {\r
206             fieldValue = 7;\r
207             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
208             out.writeByte(entry.getAugmentation(VlanPcpMatchEntry.class).getVlanPcp().byteValue());\r
209         } else if (field.equals(IpDscp.class)) {\r
210             fieldValue = 8;\r
211             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
212             out.writeByte(entry.getAugmentation(DscpMatchEntry.class).getDscp().getValue());\r
213         } else if (field.equals(IpEcn.class)) {\r
214             fieldValue = 9;\r
215             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
216             out.writeByte(entry.getAugmentation(EcnMatchEntry.class).getEcn());\r
217         } else if (field.equals(IpProto.class)) {\r
218             fieldValue = 10;\r
219             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
220             out.writeByte(entry.getAugmentation(ProtocolNumberMatchEntry.class).getProtocolNumber());\r
221         } else if (field.equals(Ipv4Src.class)) {\r
222             fieldValue = 11;\r
223             writeIpv4AddressRelatedEntry(entry, out, fieldValue);\r
224         } else if (field.equals(Ipv4Dst.class)) {\r
225             fieldValue = 12;\r
226             writeIpv4AddressRelatedEntry(entry, out, fieldValue);\r
227         } else if (field.equals(TcpSrc.class)) {\r
228             fieldValue = 13;\r
229             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
230             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
231         } else if (field.equals(TcpDst.class)) {\r
232             fieldValue = 14;\r
233             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
234             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
235         } else if (field.equals(UdpSrc.class)) {\r
236             fieldValue = 15;\r
237             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
238             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
239         } else if (field.equals(UdpDst.class)) {\r
240             fieldValue = 16;\r
241             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
242             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
243         } else if (field.equals(SctpSrc.class)) {\r
244             fieldValue = 17;\r
245             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
246             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
247         } else if (field.equals(SctpDst.class)) {\r
248             fieldValue = 18;\r
249             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
250             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
251         } else if (field.equals(Icmpv4Type.class)) {\r
252             fieldValue = 19;\r
253             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
254             out.writeByte(entry.getAugmentation(Icmpv4TypeMatchEntry.class).getIcmpv4Type());\r
255         } else if (field.equals(Icmpv4Code.class)) {\r
256             fieldValue = 20;\r
257             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
258             out.writeByte(entry.getAugmentation(Icmpv4CodeMatchEntry.class).getIcmpv4Code());\r
259         } else if (field.equals(ArpOp.class)) {\r
260             fieldValue = 21;\r
261             writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);\r
262             out.writeShort(entry.getAugmentation(OpCodeMatchEntry.class).getOpCode());\r
263         } else if (field.equals(ArpSpa.class)) {\r
264             fieldValue = 22;\r
265             writeIpv4AddressRelatedEntry(entry, out, fieldValue);\r
266         } else if (field.equals(ArpTpa.class)) {\r
267             fieldValue = 23;\r
268             writeIpv4AddressRelatedEntry(entry, out, fieldValue);\r
269         } else if (field.equals(ArpSha.class)) {\r
270             fieldValue = 24;\r
271             writeMacAddressRelatedEntry(entry, out, fieldValue);\r
272         } else if (field.equals(ArpTha.class)) {\r
273             fieldValue = 25;\r
274             writeMacAddressRelatedEntry(entry, out, fieldValue);\r
275         } else if (field.equals(Ipv6Src.class)) {\r
276             fieldValue = 26;\r
277             writeIpv6AddressRelatedEntry(entry, out, fieldValue);\r
278         } else if (field.equals(Ipv6Dst.class)) {\r
279             fieldValue = 27;\r
280             writeIpv6AddressRelatedEntry(entry, out, fieldValue);\r
281         } else if (field.equals(Ipv6Flabel.class)) {\r
282             fieldValue = 28;\r
283             fieldValue = fieldValue << 1;\r
284             if (entry.isHasMask()) {\r
285                 fieldValue = fieldValue | 1;\r
286                 out.writeByte(fieldValue);\r
287                 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
288                 out.writeByte(Integer.SIZE / Byte.SIZE + mask.length); // 20 b + mask [OF 1.3.2 spec]\r
289                 LOGGER.warn("Ipv6Flabel match entry: possible wrong length written (wrote 4 - maybe must be 3)");\r
290                 out.writeInt(entry.getAugmentation(Ipv6FlabelMatchEntry.class).getIpv6Flabel().getValue().intValue());\r
291                 out.writeBytes(entry.getAugmentation(MaskMatchEntry.class).getMask());\r
292             } else {\r
293                 out.writeByte(fieldValue);\r
294                 out.writeByte(Integer.SIZE / Byte.SIZE); // 20 b [OF 1.3.2 spec]\r
295                 LOGGER.warn("Ipv6Flabel match entry: possible wrong length written (wrote 4 - maybe must be 3)");\r
296                 out.writeInt(entry.getAugmentation(Ipv6FlabelMatchEntry.class).getIpv6Flabel().getValue().intValue());\r
297             }\r
298         } else if (field.equals(Icmpv6Type.class)) {\r
299             fieldValue = 29;\r
300             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
301             out.writeByte(entry.getAugmentation(Icmpv6TypeMatchEntry.class).getIcmpv6Type());\r
302         } else if (field.equals(Icmpv6Code.class)) {\r
303             fieldValue = 30;\r
304             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
305             out.writeByte(entry.getAugmentation(Icmpv6CodeMatchEntry.class).getIcmpv6Code());\r
306         } else if (field.equals(Ipv6NdTarget.class)) {\r
307             fieldValue = 31;\r
308             writeIpv6AddressRelatedEntry(entry, out, fieldValue);\r
309         } else if (field.equals(Ipv6NdSll.class)) {\r
310             fieldValue = 32;\r
311             writeMacAddressRelatedEntry(entry, out, fieldValue);\r
312         } else if (field.equals(Ipv6NdTll.class)) {\r
313             fieldValue = 33;\r
314             writeMacAddressRelatedEntry(entry, out, fieldValue);\r
315         } else if (field.equals(MplsLabel.class)) {\r
316             fieldValue = 34;\r
317             writeOxmFieldAndLength(out, fieldValue, Integer.SIZE / Byte.SIZE);\r
318             LOGGER.warn("MplsLabel match entry: possible wrong length written (wrote 4 - maybe must be 3)");\r
319             out.writeInt(entry.getAugmentation(MplsLabelMatchEntry.class).getMplsLabel().intValue());\r
320         } else if (field.equals(MplsTc.class)) {\r
321             fieldValue = 35;\r
322             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
323             out.writeByte(entry.getAugmentation(TcMatchEntry.class).getTc());\r
324         } else if (field.equals(MplsBos.class)) {\r
325             fieldValue = 36;\r
326             writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);\r
327             out.writeBoolean(entry.getAugmentation(BosMatchEntry.class).isBos().booleanValue());\r
328         } else if (field.equals(PbbIsid.class)) {\r
329             fieldValue = 37;\r
330             fieldValue = fieldValue << 1;\r
331             if (entry.isHasMask()) {\r
332                 fieldValue = fieldValue | 1;\r
333                 out.writeByte(fieldValue);\r
334                 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
335                 out.writeByte(Long.SIZE / Byte.SIZE + mask.length);\r
336                 LOGGER.warn("PbbIsid match entry: possible wrong length written (wrote 4 - maybe must be 3)");\r
337                 out.writeInt(entry.getAugmentation(IsidMatchEntry.class).getIsid().intValue());\r
338                 out.writeBytes(mask);\r
339             } else {\r
340                 out.writeByte(fieldValue);\r
341                 out.writeByte(Long.SIZE / Byte.SIZE);\r
342                 LOGGER.warn("PbbIsid match entry: possible wrong length written (wrote 4 - maybe must be 3)");\r
343                 out.writeInt(entry.getAugmentation(IsidMatchEntry.class).getIsid().intValue());\r
344             }\r
345         } else if (field.equals(TunnelId.class)) {\r
346             fieldValue = 38;\r
347             writeMetadataRelatedEntry(entry, out, fieldValue);\r
348         } else if (field.equals(Ipv6Exthdr.class)) {\r
349             fieldValue = 39;\r
350             fieldValue = fieldValue << 1;\r
351             PseudoField pseudoField = entry.getAugmentation(PseudoFieldMatchEntry.class).getPseudoField();\r
352             Map<Integer, Boolean> map = new HashMap<>();\r
353             map.put(0, pseudoField.isNonext());\r
354             map.put(1, pseudoField.isEsp());\r
355             map.put(2, pseudoField.isAuth());\r
356             map.put(3, pseudoField.isDest());\r
357             map.put(4, pseudoField.isFrag());\r
358             map.put(5, pseudoField.isRouter());\r
359             map.put(6, pseudoField.isHop());\r
360             map.put(7, pseudoField.isUnrep());\r
361             map.put(8, pseudoField.isUnseq());\r
362             int bitmap = ByteBufUtils.fillBitMaskFromMap(map);\r
363             if (entry.isHasMask()) {\r
364                 fieldValue = fieldValue | 1;\r
365                 out.writeByte(fieldValue);\r
366                 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
367                 out.writeByte(Short.SIZE / Byte.SIZE + mask.length);\r
368                 out.writeShort(bitmap);\r
369                 out.writeBytes(mask);\r
370             } else {\r
371                 out.writeByte(fieldValue);\r
372                 out.writeByte(Short.SIZE / Byte.SIZE);\r
373                 out.writeShort(bitmap);\r
374             }\r
375         }\r
376     }\r
377     \r
378     private static void writeOxmFieldAndLength(ByteBuf out, int fieldValue, int length) {\r
379         int fieldAndMask = fieldValue << 1;\r
380         out.writeByte(fieldAndMask);\r
381         out.writeByte(length);\r
382     }\r
383     \r
384     private static void writeMetadataRelatedEntry(MatchEntries entry, ByteBuf out, int value) {\r
385         int fieldValue = value << 1;\r
386         if (entry.isHasMask()) {\r
387             fieldValue = fieldValue | 1;\r
388             out.writeByte(fieldValue);\r
389             byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
390             out.writeByte(Long.SIZE / Byte.SIZE + mask.length);\r
391             out.writeBytes(entry.getAugmentation(MetadataMatchEntry.class).getMetadata());\r
392             out.writeBytes(mask);\r
393         } else {\r
394             out.writeByte(fieldValue);\r
395             out.writeByte(Long.SIZE / Byte.SIZE);\r
396             out.writeBytes(entry.getAugmentation(MetadataMatchEntry.class).getMetadata());\r
397         }\r
398     }\r
399     \r
400     private static void writeMacAddressRelatedEntry(MatchEntries entry, ByteBuf out, int value) {\r
401         int fieldValue = value << 1;\r
402         if (entry.isHasMask()) {\r
403             fieldValue = fieldValue | 1;\r
404             out.writeByte(fieldValue);\r
405             byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
406             out.writeByte((Integer.SIZE + Short.SIZE) / Byte.SIZE + mask.length); // 48 b + mask [OF 1.3.2 spec]\r
407             out.writeBytes(entry.getAugmentation(MacAddressMatchEntry.class).getMacAddress().getValue().getBytes());\r
408             out.writeBytes(mask);\r
409         } else {\r
410             out.writeByte(fieldValue);\r
411             out.writeByte((Integer.SIZE + Short.SIZE) / Byte.SIZE); // 48 b [OF 1.3.2 spec]\r
412             out.writeBytes(entry.getAugmentation(MacAddressMatchEntry.class).getMacAddress().getValue().getBytes());\r
413         }\r
414     }\r
415     \r
416     private static void writeIpv4AddressRelatedEntry(MatchEntries entry, ByteBuf out, int value) {\r
417         int fieldValue = value << 1;\r
418         if (entry.isHasMask()) {\r
419             fieldValue = fieldValue | 1;\r
420             out.writeByte(fieldValue);\r
421             byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
422             out.writeByte(Integer.SIZE / Byte.SIZE + mask.length);\r
423             writeIpv4Address(entry, out);\r
424             out.writeBytes(mask);\r
425         } else {\r
426             out.writeByte(fieldValue);\r
427             out.writeByte(Integer.SIZE / Byte.SIZE);\r
428             writeIpv4Address(entry, out);\r
429         }\r
430     }\r
431     \r
432     private static void writeIpv4Address(MatchEntries entry, ByteBuf out) {\r
433         String[] addressGroups = entry.getAugmentation(Ipv4AddressMatchEntry.class).getIpv4Address().getValue().split(".");\r
434         for (int i = 0; i < addressGroups.length; i++) {\r
435             out.writeByte(Integer.parseInt(addressGroups[i]));\r
436         }\r
437     }\r
438 \r
439     private static void writeIpv6AddressRelatedEntry(MatchEntries entry, ByteBuf out, int value) {\r
440         int fieldValue = value << 1;\r
441         String[] addressGroups = entry.getAugmentation(Ipv6AddressMatchEntry.class).getIpv6Address().getValue().split(":");\r
442         String[] address = parseIpv6Address(addressGroups);\r
443         if (entry.isHasMask()) {\r
444             fieldValue = fieldValue | 1;\r
445             out.writeByte(fieldValue);\r
446             byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
447             out.writeByte((8 * Short.SIZE) / Byte.SIZE + mask.length);\r
448             for (int i = 0; i < address.length; i++) {\r
449                 out.writeShort(Integer.parseInt(addressGroups[i], 16));\r
450             }\r
451             out.writeBytes(mask);\r
452         } else {\r
453             out.writeByte(fieldValue);\r
454             out.writeByte((8 * Short.SIZE) / Byte.SIZE);\r
455             for (int i = 0; i < addressGroups.length; i++) {\r
456                 out.writeShort(Integer.parseInt(addressGroups[i], 16));\r
457             }\r
458         }\r
459     }\r
460 \r
461     private static String[] parseIpv6Address(String[] addressGroups) {\r
462         final byte GROUPS_IN_IPV6_ADDRESS = 8;\r
463         int countEmpty = 0;\r
464         for (int i = 0; i < addressGroups.length; i++) {\r
465             if (addressGroups[i].equals("")){\r
466                 countEmpty++;\r
467             } \r
468         }\r
469         String[] ready = new String[GROUPS_IN_IPV6_ADDRESS];\r
470         switch (countEmpty) {\r
471         case 0:\r
472             ready = addressGroups;\r
473             break;\r
474         case 1:\r
475             int zerosToBePushed = GROUPS_IN_IPV6_ADDRESS - addressGroups.length + 1;\r
476             int pushed = 0;\r
477             for (int i = 0; i < addressGroups.length; i++) {\r
478                 if (addressGroups[i].equals("")) {\r
479                     for (int j = 0; j < zerosToBePushed; j++) {\r
480                         ready[i+j] = "0";\r
481                         pushed++;\r
482                     }\r
483                 } else {\r
484                     ready[i + pushed] = addressGroups[i];\r
485                 }\r
486             }\r
487             break;\r
488         case 2:\r
489             Arrays.fill(ready, "0");\r
490             ready[ready.length - 1] = addressGroups[addressGroups.length - 1];\r
491             break;\r
492         case 3:\r
493             Arrays.fill(ready, "0");\r
494             break;\r
495 \r
496         default:\r
497             break;\r
498         }\r
499         return ready;\r
500     }\r
501 \r
502     /**\r
503      * Computes length of match (in bytes)\r
504      * @param match\r
505      * @return length of ofp_match (excluding padding)\r
506      */\r
507     public static int computeMatchLength(Match match) {\r
508         final byte MATCH_TYPE_AND_LENGTH_SIZE = 4;\r
509         int length = 0;\r
510         if (match != null) {\r
511             length += MATCH_TYPE_AND_LENGTH_SIZE + computeMatchEntriesLength(match.getMatchEntries());\r
512         }\r
513         return length;\r
514     }\r
515 \r
516     /**\r
517      * Computes length of MatchEntries (in bytes)\r
518      * @param matchEntries list of match entries (oxm_fields)\r
519      * @return length of MatchEntries\r
520      */\r
521     public static int computeMatchEntriesLength(List<MatchEntries> matchEntries) {\r
522         final byte MATCH_ENTRY_HEADER_LENGTH = 4;\r
523         int length = 0;\r
524         if (matchEntries != null) {\r
525             for (MatchEntries entry : matchEntries) {\r
526                 length += MATCH_ENTRY_HEADER_LENGTH;\r
527                 Class<? extends MatchField> field = entry.getOxmMatchField();\r
528                 if (field.equals(InPort.class)) {\r
529                     length += Integer.SIZE / Byte.SIZE;\r
530                 } else if (field.equals(InPhyPort.class)) {\r
531                     length += Integer.SIZE / Byte.SIZE;\r
532                 } else if (field.equals(Metadata.class)) {\r
533                     length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);\r
534                 } else if (field.equals(EthDst.class)) {\r
535                     length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);\r
536                 } else if (field.equals(EthSrc.class)) {\r
537                     length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);\r
538                 } else if (field.equals(EthType.class)) {\r
539                     length += Short.SIZE / Byte.SIZE;\r
540                 } else if (field.equals(VlanVid.class)) {\r
541                     length += computePossibleMaskEntryLength(entry, Short.SIZE / Byte.SIZE);\r
542                 } else if (field.equals(VlanPcp.class)) {\r
543                     length += Byte.SIZE / Byte.SIZE;\r
544                 } else if (field.equals(IpDscp.class)) {\r
545                     length += Byte.SIZE / Byte.SIZE;\r
546                 } else if (field.equals(IpEcn.class)) {\r
547                     length += Byte.SIZE / Byte.SIZE;\r
548                 } else if (field.equals(IpProto.class)) {\r
549                     length += Byte.SIZE / Byte.SIZE;\r
550                 } else if (field.equals(Ipv4Src.class)) {\r
551                     length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);\r
552                 } else if (field.equals(Ipv4Dst.class)) {\r
553                     length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);\r
554                 } else if (field.equals(TcpSrc.class)) {\r
555                     length += Short.SIZE / Byte.SIZE;\r
556                 } else if (field.equals(TcpDst.class)) {\r
557                     length += Short.SIZE / Byte.SIZE;\r
558                 } else if (field.equals(UdpSrc.class)) {\r
559                     length += Short.SIZE / Byte.SIZE;\r
560                 } else if (field.equals(UdpDst.class)) {\r
561                     length += Short.SIZE / Byte.SIZE;\r
562                 } else if (field.equals(SctpSrc.class)) {\r
563                     length += Short.SIZE / Byte.SIZE;\r
564                 } else if (field.equals(SctpDst.class)) {\r
565                     length += Short.SIZE / Byte.SIZE;\r
566                 } else if (field.equals(Icmpv4Type.class)) {\r
567                     length += Byte.SIZE / Byte.SIZE;\r
568                 } else if (field.equals(Icmpv4Code.class)) {\r
569                     length += Byte.SIZE / Byte.SIZE;\r
570                 } else if (field.equals(ArpOp.class)) {\r
571                     length += Short.SIZE / Byte.SIZE;\r
572                 } else if (field.equals(ArpSpa.class)) {\r
573                     length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);\r
574                 } else if (field.equals(ArpTpa.class)) {\r
575                     length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);\r
576                 } else if (field.equals(ArpSha.class)) {\r
577                     length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);\r
578                 } else if (field.equals(ArpTha.class)) {\r
579                     length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);\r
580                 } else if (field.equals(Ipv6Src.class)) {\r
581                     length += computePossibleMaskEntryLength(entry, 8 * (Short.SIZE / Byte.SIZE));\r
582                 } else if (field.equals(Ipv6Dst.class)) {\r
583                     length += computePossibleMaskEntryLength(entry, 8 * (Short.SIZE / Byte.SIZE));\r
584                 } else if (field.equals(Ipv6Flabel.class)) {\r
585                     length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);\r
586                 } else if (field.equals(Icmpv6Type.class)) {\r
587                     length += Byte.SIZE / Byte.SIZE;\r
588                 } else if (field.equals(Icmpv6Code.class)) {\r
589                     length += Byte.SIZE / Byte.SIZE;\r
590                 } else if (field.equals(Ipv6NdTarget.class)) {\r
591                     length += computePossibleMaskEntryLength(entry, 8 * (Short.SIZE / Byte.SIZE));\r
592                 } else if (field.equals(Ipv6NdSll.class)) {\r
593                     length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);\r
594                 } else if (field.equals(Ipv6NdTll.class)) {\r
595                     length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);\r
596                 } else if (field.equals(MplsLabel.class)) {\r
597                     length += Integer.SIZE / Byte.SIZE;\r
598                 } else if (field.equals(MplsTc.class)) {\r
599                     length += Byte.SIZE / Byte.SIZE;\r
600                 } else if (field.equals(MplsBos.class)) {\r
601                     length += Byte.SIZE / Byte.SIZE;\r
602                 } else if (field.equals(PbbIsid.class)) {\r
603                     length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);\r
604                 } else if (field.equals(TunnelId.class)) {\r
605                     length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);\r
606                 } else if (field.equals(Ipv6Exthdr.class)) {\r
607                     length += computePossibleMaskEntryLength(entry, Short.SIZE / Byte.SIZE);\r
608                 }\r
609             }\r
610         }\r
611         return length;\r
612     }\r
613 \r
614     private static int computePossibleMaskEntryLength(MatchEntries entry, int length) {\r
615         int entryLength = length;\r
616         if (entry.isHasMask()) {\r
617             entryLength *= 2;\r
618         }\r
619         return entryLength;\r
620     }\r
621 \r
622 }\r