d4729f6b2aafc637ebaff08b625788e60a0cd8f9
[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[] addressGroups = entry.getAugmentation(Ipv6AddressMatchEntry.class).getIpv6Address().getValue().split(":");\r
444         String[] address = parseIpv6Address(addressGroups);\r
445         if (entry.isHasMask()) {\r
446             fieldValue = fieldValue | 1;\r
447             out.writeByte(fieldValue);\r
448             byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
449             out.writeByte(EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES + mask.length);\r
450             for (int i = 0; i < address.length; i++) {\r
451                 out.writeShort(Integer.parseInt(addressGroups[i], 16));\r
452             }\r
453             out.writeBytes(mask);\r
454         } else {\r
455             out.writeByte(fieldValue);\r
456             out.writeByte(EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES);\r
457             for (int i = 0; i < addressGroups.length; i++) {\r
458                 out.writeShort(Integer.parseInt(addressGroups[i], 16));\r
459             }\r
460         }\r
461     }\r
462 \r
463     private static String[] parseIpv6Address(String[] addressGroups) {\r
464         int countEmpty = 0;\r
465         for (int i = 0; i < addressGroups.length; i++) {\r
466             if (addressGroups[i].equals("")){\r
467                 countEmpty++;\r
468             }\r
469         }\r
470         String[] ready = new String[EncodeConstants.GROUPS_IN_IPV6_ADDRESS];\r
471         switch (countEmpty) {\r
472         case 0:\r
473             ready = addressGroups;\r
474             break;\r
475         case 1:\r
476             int zerosToBePushed = EncodeConstants.GROUPS_IN_IPV6_ADDRESS - addressGroups.length + 1;\r
477             int pushed = 0;\r
478             for (int i = 0; i < addressGroups.length; i++) {\r
479                 if (addressGroups[i].equals("")) {\r
480                     for (int j = 0; j < zerosToBePushed; j++) {\r
481                         ready[i+j] = "0";\r
482                         pushed++;\r
483                     }\r
484                 } else {\r
485                     ready[i + pushed] = addressGroups[i];\r
486                 }\r
487             }\r
488             break;\r
489         case 2:\r
490             Arrays.fill(ready, "0");\r
491             ready[ready.length - 1] = addressGroups[addressGroups.length - 1];\r
492             break;\r
493         case 3:\r
494             Arrays.fill(ready, "0");\r
495             break;\r
496 \r
497         default:\r
498             break;\r
499         }\r
500         return ready;\r
501     }\r
502 \r
503     /**\r
504      * Computes length of match (in bytes)\r
505      * @param match\r
506      * @return length of ofp_match (excluding padding)\r
507      */\r
508     public static int computeMatchLengthInternal(Match match) {\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 match (in bytes)\r
518      * @param match\r
519      * @return length of ofp_match (excluding padding)\r
520      */\r
521     public static int computeMatchLength(Match match) {\r
522         int length = computeMatchLengthInternal(match);\r
523         int paddingRemainder = length % EncodeConstants.PADDING;\r
524         if (paddingRemainder != 0) {\r
525             length += EncodeConstants.PADDING - paddingRemainder;\r
526         }\r
527         return length;\r
528     }\r
529 \r
530     /**\r
531      * Computes length of MatchEntries (in bytes)\r
532      * @param matchEntries list of match entries (oxm_fields)\r
533      * @return length of MatchEntries\r
534      */\r
535     public static int computeMatchEntriesLength(List<MatchEntries> matchEntries) {\r
536         int length = 0;\r
537         if (matchEntries != null) {\r
538             for (MatchEntries entry : matchEntries) {\r
539                 length += MATCH_ENTRY_HEADER_LENGTH;\r
540                 Class<? extends MatchField> field = entry.getOxmMatchField();\r
541                 if (field.isAssignableFrom(InPort.class)) {\r
542                     length += EncodeConstants.SIZE_OF_INT_IN_BYTES;\r
543                 } else if (field.isAssignableFrom(InPhyPort.class)) {\r
544                     length += EncodeConstants.SIZE_OF_INT_IN_BYTES;\r
545                 } else if (field.isAssignableFrom(Metadata.class)) {\r
546                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_LONG_IN_BYTES);\r
547                 } else if (field.isAssignableFrom(EthDst.class)) {\r
548                     length += computePossibleMaskEntryLength(entry, EncodeConstants.MAC_ADDRESS_LENGTH);\r
549                 } else if (field.isAssignableFrom(EthSrc.class)) {\r
550                     length += computePossibleMaskEntryLength(entry, EncodeConstants.MAC_ADDRESS_LENGTH);\r
551                 } else if (field.isAssignableFrom(EthType.class)) {\r
552                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
553                 } else if (field.isAssignableFrom(VlanVid.class)) {\r
554                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);\r
555                 } else if (field.isAssignableFrom(VlanPcp.class)) {\r
556                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
557                 } else if (field.isAssignableFrom(IpDscp.class)) {\r
558                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
559                 } else if (field.isAssignableFrom(IpEcn.class)) {\r
560                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
561                 } else if (field.isAssignableFrom(IpProto.class)) {\r
562                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
563                 } else if (field.isAssignableFrom(Ipv4Src.class)) {\r
564                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);\r
565                 } else if (field.isAssignableFrom(Ipv4Dst.class)) {\r
566                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);\r
567                 } else if (field.isAssignableFrom(TcpSrc.class)) {\r
568                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
569                 } else if (field.isAssignableFrom(TcpDst.class)) {\r
570                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
571                 } else if (field.isAssignableFrom(UdpSrc.class)) {\r
572                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
573                 } else if (field.isAssignableFrom(UdpDst.class)) {\r
574                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
575                 } else if (field.isAssignableFrom(SctpSrc.class)) {\r
576                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
577                 } else if (field.isAssignableFrom(SctpDst.class)) {\r
578                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
579                 } else if (field.isAssignableFrom(Icmpv4Type.class)) {\r
580                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
581                 } else if (field.isAssignableFrom(Icmpv4Code.class)) {\r
582                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
583                 } else if (field.isAssignableFrom(ArpOp.class)) {\r
584                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
585                 } else if (field.isAssignableFrom(ArpSpa.class)) {\r
586                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);\r
587                 } else if (field.isAssignableFrom(ArpTpa.class)) {\r
588                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);\r
589                 } else if (field.isAssignableFrom(ArpSha.class)) {\r
590                     length += computePossibleMaskEntryLength(entry, EncodeConstants.MAC_ADDRESS_LENGTH);\r
591                 } else if (field.isAssignableFrom(ArpTha.class)) {\r
592                     length += computePossibleMaskEntryLength(entry, EncodeConstants.MAC_ADDRESS_LENGTH);\r
593                 } else if (field.isAssignableFrom(Ipv6Src.class)) {\r
594                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES);\r
595                 } else if (field.isAssignableFrom(Ipv6Dst.class)) {\r
596                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES);\r
597                 } else if (field.isAssignableFrom(Ipv6Flabel.class)) {\r
598                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);\r
599                 } else if (field.isAssignableFrom(Icmpv6Type.class)) {\r
600                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
601                 } else if (field.isAssignableFrom(Icmpv6Code.class)) {\r
602                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
603                 } else if (field.isAssignableFrom(Ipv6NdTarget.class)) {\r
604                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES);\r
605                 } else if (field.isAssignableFrom(Ipv6NdSll.class)) {\r
606                     length += computePossibleMaskEntryLength(entry, EncodeConstants.MAC_ADDRESS_LENGTH);\r
607                 } else if (field.isAssignableFrom(Ipv6NdTll.class)) {\r
608                     length += computePossibleMaskEntryLength(entry, EncodeConstants.MAC_ADDRESS_LENGTH);\r
609                 } else if (field.isAssignableFrom(MplsLabel.class)) {\r
610                     length += EncodeConstants.SIZE_OF_INT_IN_BYTES;\r
611                 } else if (field.isAssignableFrom(MplsTc.class)) {\r
612                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
613                 } else if (field.isAssignableFrom(MplsBos.class)) {\r
614                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
615                 } else if (field.isAssignableFrom(PbbIsid.class)) {\r
616                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);\r
617                 } else if (field.isAssignableFrom(TunnelId.class)) {\r
618                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_LONG_IN_BYTES);\r
619                 } else if (field.isAssignableFrom(Ipv6Exthdr.class)) {\r
620                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);\r
621                 }\r
622             }\r
623         }\r
624         return length;\r
625     }\r
626 \r
627     private static int computePossibleMaskEntryLength(MatchEntries entry, int length) {\r
628         int entryLength = length;\r
629         if (entry.isHasMask()) {\r
630             entryLength *= 2;\r
631         }\r
632         return entryLength;\r
633     }\r
634 \r
635 }\r