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