Quickfix - Vlan-vid match entry
[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();\r
191             if (vlanVid.isCfiBit()) {\r
192                 short cfi = 1 << 12; // 13-th bit\r
193                 vlanVidValue = vlanVidValue | cfi;\r
194             }\r
195             if (entry.isHasMask()) {\r
196                 fieldValue = fieldValue | 1;\r
197                 out.writeByte(fieldValue);\r
198                 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
199                 out.writeByte(EncodeConstants.SIZE_OF_SHORT_IN_BYTES + mask.length);\r
200                 out.writeShort(vlanVidValue);\r
201                 out.writeBytes(mask);\r
202             } else {\r
203                 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);\r
204                 out.writeShort(vlanVidValue);\r
205             }\r
206         } else if (field.isAssignableFrom(VlanPcp.class)) {\r
207             fieldValue = 7;\r
208             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);\r
209             out.writeByte(entry.getAugmentation(VlanPcpMatchEntry.class).getVlanPcp().byteValue());\r
210         } else if (field.isAssignableFrom(IpDscp.class)) {\r
211             fieldValue = 8;\r
212             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);\r
213             out.writeByte(entry.getAugmentation(DscpMatchEntry.class).getDscp().getValue());\r
214         } else if (field.isAssignableFrom(IpEcn.class)) {\r
215             fieldValue = 9;\r
216             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);\r
217             out.writeByte(entry.getAugmentation(EcnMatchEntry.class).getEcn());\r
218         } else if (field.isAssignableFrom(IpProto.class)) {\r
219             fieldValue = 10;\r
220             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);\r
221             out.writeByte(entry.getAugmentation(ProtocolNumberMatchEntry.class).getProtocolNumber());\r
222         } else if (field.isAssignableFrom(Ipv4Src.class)) {\r
223             fieldValue = 11;\r
224             writeIpv4AddressRelatedEntry(entry, out, fieldValue);\r
225         } else if (field.isAssignableFrom(Ipv4Dst.class)) {\r
226             fieldValue = 12;\r
227             writeIpv4AddressRelatedEntry(entry, out, fieldValue);\r
228         } else if (field.isAssignableFrom(TcpSrc.class)) {\r
229             fieldValue = 13;\r
230             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);\r
231             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
232         } else if (field.isAssignableFrom(TcpDst.class)) {\r
233             fieldValue = 14;\r
234             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);\r
235             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
236         } else if (field.isAssignableFrom(UdpSrc.class)) {\r
237             fieldValue = 15;\r
238             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);\r
239             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
240         } else if (field.isAssignableFrom(UdpDst.class)) {\r
241             fieldValue = 16;\r
242             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);\r
243             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
244         } else if (field.isAssignableFrom(SctpSrc.class)) {\r
245             fieldValue = 17;\r
246             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);\r
247             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
248         } else if (field.isAssignableFrom(SctpDst.class)) {\r
249             fieldValue = 18;\r
250             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);\r
251             out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());\r
252         } else if (field.isAssignableFrom(Icmpv4Type.class)) {\r
253             fieldValue = 19;\r
254             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);\r
255             out.writeByte(entry.getAugmentation(Icmpv4TypeMatchEntry.class).getIcmpv4Type());\r
256         } else if (field.isAssignableFrom(Icmpv4Code.class)) {\r
257             fieldValue = 20;\r
258             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);\r
259             out.writeByte(entry.getAugmentation(Icmpv4CodeMatchEntry.class).getIcmpv4Code());\r
260         } else if (field.isAssignableFrom(ArpOp.class)) {\r
261             fieldValue = 21;\r
262             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);\r
263             out.writeShort(entry.getAugmentation(OpCodeMatchEntry.class).getOpCode());\r
264         } else if (field.isAssignableFrom(ArpSpa.class)) {\r
265             fieldValue = 22;\r
266             writeIpv4AddressRelatedEntry(entry, out, fieldValue);\r
267         } else if (field.isAssignableFrom(ArpTpa.class)) {\r
268             fieldValue = 23;\r
269             writeIpv4AddressRelatedEntry(entry, out, fieldValue);\r
270         } else if (field.isAssignableFrom(ArpSha.class)) {\r
271             fieldValue = 24;\r
272             writeMacAddressRelatedEntry(entry, out, fieldValue);\r
273         } else if (field.isAssignableFrom(ArpTha.class)) {\r
274             fieldValue = 25;\r
275             writeMacAddressRelatedEntry(entry, out, fieldValue);\r
276         } else if (field.isAssignableFrom(Ipv6Src.class)) {\r
277             fieldValue = 26;\r
278             writeIpv6AddressRelatedEntry(entry, out, fieldValue);\r
279         } else if (field.isAssignableFrom(Ipv6Dst.class)) {\r
280             fieldValue = 27;\r
281             writeIpv6AddressRelatedEntry(entry, out, fieldValue);\r
282         } else if (field.isAssignableFrom(Ipv6Flabel.class)) {\r
283             fieldValue = 28;\r
284             fieldValue = fieldValue << 1;\r
285             if (entry.isHasMask()) {\r
286                 fieldValue = fieldValue | 1;\r
287                 out.writeByte(fieldValue);\r
288                 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
289                 out.writeByte(EncodeConstants.SIZE_OF_INT_IN_BYTES + mask.length); // 20 b + mask [OF 1.3.2 spec]\r
290                 LOGGER.warn("Ipv6Flabel match entry: possible wrong length written (wrote 4 - maybe must be 3)");\r
291                 out.writeInt(entry.getAugmentation(Ipv6FlabelMatchEntry.class).getIpv6Flabel().getValue().intValue());\r
292                 out.writeBytes(entry.getAugmentation(MaskMatchEntry.class).getMask());\r
293             } else {\r
294                 out.writeByte(fieldValue);\r
295                 out.writeByte(EncodeConstants.SIZE_OF_INT_IN_BYTES); // 20 b [OF 1.3.2 spec]\r
296                 LOGGER.warn("Ipv6Flabel match entry: possible wrong length written (wrote 4 - maybe must be 3)");\r
297                 out.writeInt(entry.getAugmentation(Ipv6FlabelMatchEntry.class).getIpv6Flabel().getValue().intValue());\r
298             }\r
299         } else if (field.isAssignableFrom(Icmpv6Type.class)) {\r
300             fieldValue = 29;\r
301             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);\r
302             out.writeByte(entry.getAugmentation(Icmpv6TypeMatchEntry.class).getIcmpv6Type());\r
303         } else if (field.isAssignableFrom(Icmpv6Code.class)) {\r
304             fieldValue = 30;\r
305             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);\r
306             out.writeByte(entry.getAugmentation(Icmpv6CodeMatchEntry.class).getIcmpv6Code());\r
307         } else if (field.isAssignableFrom(Ipv6NdTarget.class)) {\r
308             fieldValue = 31;\r
309             writeIpv6AddressRelatedEntry(entry, out, fieldValue);\r
310         } else if (field.isAssignableFrom(Ipv6NdSll.class)) {\r
311             fieldValue = 32;\r
312             writeMacAddressRelatedEntry(entry, out, fieldValue);\r
313         } else if (field.isAssignableFrom(Ipv6NdTll.class)) {\r
314             fieldValue = 33;\r
315             writeMacAddressRelatedEntry(entry, out, fieldValue);\r
316         } else if (field.isAssignableFrom(MplsLabel.class)) {\r
317             fieldValue = 34;\r
318             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_INT_IN_BYTES);\r
319             LOGGER.warn("MplsLabel match entry: possible wrong length written (wrote 4 - maybe must be 3)");\r
320             out.writeInt(entry.getAugmentation(MplsLabelMatchEntry.class).getMplsLabel().intValue());\r
321         } else if (field.isAssignableFrom(MplsTc.class)) {\r
322             fieldValue = 35;\r
323             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);\r
324             out.writeByte(entry.getAugmentation(TcMatchEntry.class).getTc());\r
325         } else if (field.isAssignableFrom(MplsBos.class)) {\r
326             fieldValue = 36;\r
327             writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);\r
328             out.writeBoolean(entry.getAugmentation(BosMatchEntry.class).isBos().booleanValue());\r
329         } else if (field.isAssignableFrom(PbbIsid.class)) {\r
330             fieldValue = 37;\r
331             fieldValue = fieldValue << 1;\r
332             if (entry.isHasMask()) {\r
333                 fieldValue = fieldValue | 1;\r
334                 out.writeByte(fieldValue);\r
335                 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
336                 out.writeByte(EncodeConstants.SIZE_OF_LONG_IN_BYTES + mask.length);\r
337                 LOGGER.warn("PbbIsid match entry: possible wrong length written (wrote 4 - maybe must be 3)");\r
338                 out.writeInt(entry.getAugmentation(IsidMatchEntry.class).getIsid().intValue());\r
339                 out.writeBytes(mask);\r
340             } else {\r
341                 out.writeByte(fieldValue);\r
342                 out.writeByte(EncodeConstants.SIZE_OF_LONG_IN_BYTES);\r
343                 LOGGER.warn("PbbIsid match entry: possible wrong length written (wrote 4 - maybe must be 3)");\r
344                 out.writeInt(entry.getAugmentation(IsidMatchEntry.class).getIsid().intValue());\r
345             }\r
346         } else if (field.isAssignableFrom(TunnelId.class)) {\r
347             fieldValue = 38;\r
348             writeMetadataRelatedEntry(entry, out, fieldValue);\r
349         } else if (field.isAssignableFrom(Ipv6Exthdr.class)) {\r
350             fieldValue = 39;\r
351             fieldValue = fieldValue << 1;\r
352             PseudoField pseudoField = entry.getAugmentation(PseudoFieldMatchEntry.class).getPseudoField();\r
353             Map<Integer, Boolean> map = new HashMap<>();\r
354             map.put(0, pseudoField.isNonext());\r
355             map.put(1, pseudoField.isEsp());\r
356             map.put(2, pseudoField.isAuth());\r
357             map.put(3, pseudoField.isDest());\r
358             map.put(4, pseudoField.isFrag());\r
359             map.put(5, pseudoField.isRouter());\r
360             map.put(6, pseudoField.isHop());\r
361             map.put(7, pseudoField.isUnrep());\r
362             map.put(8, pseudoField.isUnseq());\r
363             int bitmap = ByteBufUtils.fillBitMaskFromMap(map);\r
364             if (entry.isHasMask()) {\r
365                 fieldValue = fieldValue | 1;\r
366                 out.writeByte(fieldValue);\r
367                 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
368                 out.writeByte(EncodeConstants.SIZE_OF_SHORT_IN_BYTES + mask.length);\r
369                 out.writeShort(bitmap);\r
370                 out.writeBytes(mask);\r
371             } else {\r
372                 out.writeByte(fieldValue);\r
373                 out.writeByte(EncodeConstants.SIZE_OF_SHORT_IN_BYTES);\r
374                 out.writeShort(bitmap);\r
375             }\r
376         }\r
377     }\r
378     \r
379     private static void writeOxmFieldAndLength(ByteBuf out, int fieldValue, int length) {\r
380         int fieldAndMask = fieldValue << 1;\r
381         out.writeByte(fieldAndMask);\r
382         out.writeByte(length);\r
383     }\r
384     \r
385     private static void writeMetadataRelatedEntry(MatchEntries entry, ByteBuf out, int value) {\r
386         int fieldValue = value << 1;\r
387         if (entry.isHasMask()) {\r
388             fieldValue = fieldValue | 1;\r
389             out.writeByte(fieldValue);\r
390             byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
391             out.writeByte(EncodeConstants.SIZE_OF_LONG_IN_BYTES + mask.length);\r
392             out.writeBytes(entry.getAugmentation(MetadataMatchEntry.class).getMetadata());\r
393             out.writeBytes(mask);\r
394         } else {\r
395             out.writeByte(fieldValue);\r
396             out.writeByte(EncodeConstants.SIZE_OF_LONG_IN_BYTES);\r
397             out.writeBytes(entry.getAugmentation(MetadataMatchEntry.class).getMetadata());\r
398         }\r
399     }\r
400     \r
401     private static void writeMacAddressRelatedEntry(MatchEntries entry, ByteBuf out, int value) {\r
402         int fieldValue = value << 1;\r
403         if (entry.isHasMask()) {\r
404             fieldValue = fieldValue | 1;\r
405             out.writeByte(fieldValue);\r
406             byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
407             out.writeByte(EncodeConstants.MAC_ADDRESS_LENGTH + mask.length); // 48 b + mask [OF 1.3.2 spec]\r
408             String macAddress = entry.getAugmentation(MacAddressMatchEntry.class).getMacAddress().getValue();\r
409             out.writeBytes(ByteBufUtils.macAddressToBytes(macAddress));\r
410             out.writeBytes(mask);\r
411         } else {\r
412             out.writeByte(fieldValue);\r
413             out.writeByte(EncodeConstants.MAC_ADDRESS_LENGTH); // 48 b [OF 1.3.2 spec]\r
414             String macAddress = entry.getAugmentation(MacAddressMatchEntry.class).getMacAddress().getValue();\r
415             out.writeBytes(ByteBufUtils.macAddressToBytes(macAddress));\r
416         }\r
417     }\r
418     \r
419     private static void writeIpv4AddressRelatedEntry(MatchEntries entry, ByteBuf out, int value) {\r
420         int fieldValue = value << 1;\r
421         if (entry.isHasMask()) {\r
422             fieldValue = fieldValue | 1;\r
423             out.writeByte(fieldValue);\r
424             byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
425             out.writeByte(EncodeConstants.SIZE_OF_INT_IN_BYTES + mask.length);\r
426             writeIpv4Address(entry, out);\r
427             out.writeBytes(mask);\r
428         } else {\r
429             out.writeByte(fieldValue);\r
430             out.writeByte(EncodeConstants.SIZE_OF_INT_IN_BYTES);\r
431             writeIpv4Address(entry, out);\r
432         }\r
433     }\r
434     \r
435     private static void writeIpv4Address(MatchEntries entry, ByteBuf out) {\r
436         String[] addressGroups = entry.getAugmentation(Ipv4AddressMatchEntry.class).getIpv4Address().getValue().split("\\.");\r
437         for (int i = 0; i < addressGroups.length; i++) {\r
438             out.writeByte(Integer.parseInt(addressGroups[i]));\r
439         }\r
440     }\r
441 \r
442     private static void writeIpv6AddressRelatedEntry(MatchEntries entry, ByteBuf out, int value) {\r
443         int fieldValue = value << 1;\r
444         String[] addressGroups = entry.getAugmentation(Ipv6AddressMatchEntry.class).getIpv6Address().getValue().split(":");\r
445         String[] address = parseIpv6Address(addressGroups);\r
446         if (entry.isHasMask()) {\r
447             fieldValue = fieldValue | 1;\r
448             out.writeByte(fieldValue);\r
449             byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();\r
450             out.writeByte(EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES + mask.length);\r
451             for (int i = 0; i < address.length; i++) {\r
452                 out.writeShort(Integer.parseInt(addressGroups[i], 16));\r
453             }\r
454             out.writeBytes(mask);\r
455         } else {\r
456             out.writeByte(fieldValue);\r
457             out.writeByte(EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES);\r
458             for (int i = 0; i < addressGroups.length; i++) {\r
459                 out.writeShort(Integer.parseInt(addressGroups[i], 16));\r
460             }\r
461         }\r
462     }\r
463 \r
464     private static String[] parseIpv6Address(String[] addressGroups) {\r
465         int countEmpty = 0;\r
466         for (int i = 0; i < addressGroups.length; i++) {\r
467             if (addressGroups[i].equals("")){\r
468                 countEmpty++;\r
469             } \r
470         }\r
471         String[] ready = new String[EncodeConstants.GROUPS_IN_IPV6_ADDRESS];\r
472         switch (countEmpty) {\r
473         case 0:\r
474             ready = addressGroups;\r
475             break;\r
476         case 1:\r
477             int zerosToBePushed = EncodeConstants.GROUPS_IN_IPV6_ADDRESS - addressGroups.length + 1;\r
478             int pushed = 0;\r
479             for (int i = 0; i < addressGroups.length; i++) {\r
480                 if (addressGroups[i].equals("")) {\r
481                     for (int j = 0; j < zerosToBePushed; j++) {\r
482                         ready[i+j] = "0";\r
483                         pushed++;\r
484                     }\r
485                 } else {\r
486                     ready[i + pushed] = addressGroups[i];\r
487                 }\r
488             }\r
489             break;\r
490         case 2:\r
491             Arrays.fill(ready, "0");\r
492             ready[ready.length - 1] = addressGroups[addressGroups.length - 1];\r
493             break;\r
494         case 3:\r
495             Arrays.fill(ready, "0");\r
496             break;\r
497 \r
498         default:\r
499             break;\r
500         }\r
501         return ready;\r
502     }\r
503 \r
504     /**\r
505      * Computes length of match (in bytes)\r
506      * @param match\r
507      * @return length of ofp_match (excluding padding)\r
508      */\r
509     public static int computeMatchLengthInternal(Match match) {\r
510         int length = 0;\r
511         if (match != null) {\r
512             length += MATCH_TYPE_AND_LENGTH_SIZE + computeMatchEntriesLength(match.getMatchEntries());\r
513         }\r
514         return length;\r
515     }\r
516     \r
517     /**\r
518      * Computes length of match (in bytes)\r
519      * @param match\r
520      * @return length of ofp_match (excluding padding)\r
521      */\r
522     public static int computeMatchLength(Match match) {\r
523         int length = computeMatchLengthInternal(match);\r
524         int paddingRemainder = length % EncodeConstants.PADDING;\r
525         if (paddingRemainder != 0) {\r
526             length += EncodeConstants.PADDING - paddingRemainder;\r
527         }\r
528         return length;\r
529     }\r
530 \r
531     /**\r
532      * Computes length of MatchEntries (in bytes)\r
533      * @param matchEntries list of match entries (oxm_fields)\r
534      * @return length of MatchEntries\r
535      */\r
536     public static int computeMatchEntriesLength(List<MatchEntries> matchEntries) {\r
537         int length = 0;\r
538         if (matchEntries != null) {\r
539             for (MatchEntries entry : matchEntries) {\r
540                 length += MATCH_ENTRY_HEADER_LENGTH;\r
541                 Class<? extends MatchField> field = entry.getOxmMatchField();\r
542                 if (field.isAssignableFrom(InPort.class)) {\r
543                     length += EncodeConstants.SIZE_OF_INT_IN_BYTES;\r
544                 } else if (field.isAssignableFrom(InPhyPort.class)) {\r
545                     length += EncodeConstants.SIZE_OF_INT_IN_BYTES;\r
546                 } else if (field.isAssignableFrom(Metadata.class)) {\r
547                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_LONG_IN_BYTES);\r
548                 } else if (field.isAssignableFrom(EthDst.class)) {\r
549                     length += computePossibleMaskEntryLength(entry, EncodeConstants.MAC_ADDRESS_LENGTH);\r
550                 } else if (field.isAssignableFrom(EthSrc.class)) {\r
551                     length += computePossibleMaskEntryLength(entry, EncodeConstants.MAC_ADDRESS_LENGTH);\r
552                 } else if (field.isAssignableFrom(EthType.class)) {\r
553                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
554                 } else if (field.isAssignableFrom(VlanVid.class)) {\r
555                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);\r
556                 } else if (field.isAssignableFrom(VlanPcp.class)) {\r
557                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
558                 } else if (field.isAssignableFrom(IpDscp.class)) {\r
559                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
560                 } else if (field.isAssignableFrom(IpEcn.class)) {\r
561                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
562                 } else if (field.isAssignableFrom(IpProto.class)) {\r
563                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
564                 } else if (field.isAssignableFrom(Ipv4Src.class)) {\r
565                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);\r
566                 } else if (field.isAssignableFrom(Ipv4Dst.class)) {\r
567                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);\r
568                 } else if (field.isAssignableFrom(TcpSrc.class)) {\r
569                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
570                 } else if (field.isAssignableFrom(TcpDst.class)) {\r
571                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
572                 } else if (field.isAssignableFrom(UdpSrc.class)) {\r
573                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
574                 } else if (field.isAssignableFrom(UdpDst.class)) {\r
575                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
576                 } else if (field.isAssignableFrom(SctpSrc.class)) {\r
577                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
578                 } else if (field.isAssignableFrom(SctpDst.class)) {\r
579                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
580                 } else if (field.isAssignableFrom(Icmpv4Type.class)) {\r
581                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
582                 } else if (field.isAssignableFrom(Icmpv4Code.class)) {\r
583                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
584                 } else if (field.isAssignableFrom(ArpOp.class)) {\r
585                     length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;\r
586                 } else if (field.isAssignableFrom(ArpSpa.class)) {\r
587                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);\r
588                 } else if (field.isAssignableFrom(ArpTpa.class)) {\r
589                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);\r
590                 } else if (field.isAssignableFrom(ArpSha.class)) {\r
591                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_LONG_IN_BYTES);\r
592                 } else if (field.isAssignableFrom(ArpTha.class)) {\r
593                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_LONG_IN_BYTES);\r
594                 } else if (field.isAssignableFrom(Ipv6Src.class)) {\r
595                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES);\r
596                 } else if (field.isAssignableFrom(Ipv6Dst.class)) {\r
597                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES);\r
598                 } else if (field.isAssignableFrom(Ipv6Flabel.class)) {\r
599                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);\r
600                 } else if (field.isAssignableFrom(Icmpv6Type.class)) {\r
601                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
602                 } else if (field.isAssignableFrom(Icmpv6Code.class)) {\r
603                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
604                 } else if (field.isAssignableFrom(Ipv6NdTarget.class)) {\r
605                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES);\r
606                 } else if (field.isAssignableFrom(Ipv6NdSll.class)) {\r
607                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_LONG_IN_BYTES);\r
608                 } else if (field.isAssignableFrom(Ipv6NdTll.class)) {\r
609                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_LONG_IN_BYTES);\r
610                 } else if (field.isAssignableFrom(MplsLabel.class)) {\r
611                     length += EncodeConstants.SIZE_OF_INT_IN_BYTES;\r
612                 } else if (field.isAssignableFrom(MplsTc.class)) {\r
613                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
614                 } else if (field.isAssignableFrom(MplsBos.class)) {\r
615                     length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;\r
616                 } else if (field.isAssignableFrom(PbbIsid.class)) {\r
617                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);\r
618                 } else if (field.isAssignableFrom(TunnelId.class)) {\r
619                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_LONG_IN_BYTES);\r
620                 } else if (field.isAssignableFrom(Ipv6Exthdr.class)) {\r
621                     length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);\r
622                 }\r
623             }\r
624         }\r
625         return length;\r
626     }\r
627 \r
628     private static int computePossibleMaskEntryLength(MatchEntries entry, int length) {\r
629         int entryLength = length;\r
630         if (entry.isHasMask()) {\r
631             entryLength *= 2;\r
632         }\r
633         return entryLength;\r
634     }\r
635 \r
636 }\r