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