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