2 * Copyright (c) 2013 Pantheon Technologies s.r.o. and others. All rights reserved.
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
9 package org.opendaylight.openflowjava.protocol.impl.util;
11 import io.netty.buffer.ByteBuf;
13 import java.util.Arrays;
14 import java.util.HashMap;
15 import java.util.List;
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;
97 * Serializes ofp_match (OpenFlow v1.3) and its oxm_fields structures
98 * @author michal.polkorab
99 * @author timotej.kubas
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;
113 * Encodes match (OpenFlow v1.3)
114 * @param match ofp_match object
115 * @param out output ByteBuf
117 public static void encodeMatch(Match match, ByteBuf out) {
119 LOGGER.debug("Match is null");
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);
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);
142 * Encodes MatchEntries
143 * @param matchEntries list of match entries (oxm_fields)
144 * @param out output ByteBuf
146 public static void encodeMatchEntries(List<MatchEntries> matchEntries, ByteBuf out) {
147 if (matchEntries == null) {
148 LOGGER.warn("Match entries are null");
151 for (MatchEntries entry : matchEntries) {
152 encodeClass(entry.getOxmClass(), out);
153 encodeRest(entry, out);
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);
169 private static void encodeRest(MatchEntries entry, ByteBuf out) {
171 Class<? extends MatchField> field = entry.getOxmMatchField();
172 if (field.isAssignableFrom(InPort.class)) {
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)) {
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)) {
182 writeMetadataRelatedEntry(entry, out, fieldValue);
183 } else if (field.isAssignableFrom(EthDst.class)) {
185 writeMacAddressRelatedEntry(entry, out, fieldValue);
186 } else if (field.isAssignableFrom(EthSrc.class)) {
188 writeMacAddressRelatedEntry(entry, out, fieldValue);
189 } else if (field.isAssignableFrom(EthType.class)) {
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)) {
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;
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);
210 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
211 out.writeShort(vlanVidValue);
213 } else if (field.isAssignableFrom(VlanPcp.class)) {
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)) {
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)) {
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)) {
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)) {
231 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
232 } else if (field.isAssignableFrom(Ipv4Dst.class)) {
234 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
235 } else if (field.isAssignableFrom(TcpSrc.class)) {
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)) {
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)) {
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)) {
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)) {
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)) {
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)) {
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)) {
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)) {
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)) {
273 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
274 } else if (field.isAssignableFrom(ArpTpa.class)) {
276 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
277 } else if (field.isAssignableFrom(ArpSha.class)) {
279 writeMacAddressRelatedEntry(entry, out, fieldValue);
280 } else if (field.isAssignableFrom(ArpTha.class)) {
282 writeMacAddressRelatedEntry(entry, out, fieldValue);
283 } else if (field.isAssignableFrom(Ipv6Src.class)) {
285 writeIpv6AddressRelatedEntry(entry, out, fieldValue);
286 } else if (field.isAssignableFrom(Ipv6Dst.class)) {
288 writeIpv6AddressRelatedEntry(entry, out, fieldValue);
289 } else if (field.isAssignableFrom(Ipv6Flabel.class)) {
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());
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());
306 } else if (field.isAssignableFrom(Icmpv6Type.class)) {
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)) {
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)) {
316 writeIpv6AddressRelatedEntry(entry, out, fieldValue);
317 } else if (field.isAssignableFrom(Ipv6NdSll.class)) {
319 writeMacAddressRelatedEntry(entry, out, fieldValue);
320 } else if (field.isAssignableFrom(Ipv6NdTll.class)) {
322 writeMacAddressRelatedEntry(entry, out, fieldValue);
323 } else if (field.isAssignableFrom(MplsLabel.class)) {
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)) {
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)) {
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)) {
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);
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());
353 } else if (field.isAssignableFrom(TunnelId.class)) {
355 writeMetadataRelatedEntry(entry, out, fieldValue);
356 } else if (field.isAssignableFrom(Ipv6Exthdr.class)) {
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);
379 out.writeByte(fieldValue);
380 out.writeByte(EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
381 out.writeShort(bitmap);
386 private static void writeOxmFieldAndLength(ByteBuf out, int fieldValue, int length) {
387 int fieldAndMask = fieldValue << 1;
388 out.writeByte(fieldAndMask);
389 out.writeByte(length);
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);
402 out.writeByte(fieldValue);
403 out.writeByte(EncodeConstants.SIZE_OF_LONG_IN_BYTES);
404 out.writeBytes(entry.getAugmentation(MetadataMatchEntry.class).getMetadata());
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);
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));
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);
436 out.writeByte(fieldValue);
437 out.writeByte(EncodeConstants.SIZE_OF_INT_IN_BYTES);
438 writeIpv4Address(entry, out);
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]));
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();
453 if (textAddress.equals("::")) {
454 address = new String[EncodeConstants.GROUPS_IN_IPV6_ADDRESS];
455 Arrays.fill(address, "0");
457 address = parseIpv6Address(textAddress.split(":"));
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));
467 out.writeBytes(mask);
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));
477 private static String[] parseIpv6Address(String[] addressGroups) {
479 for (int i = 0; i < addressGroups.length; i++) {
480 if (addressGroups[i].equals("")){
484 String[] ready = new String[EncodeConstants.GROUPS_IN_IPV6_ADDRESS];
485 switch (countEmpty) {
487 ready = addressGroups;
490 int zerosToBePushed = EncodeConstants.GROUPS_IN_IPV6_ADDRESS - addressGroups.length + 1;
492 for (int i = 0; i < addressGroups.length; i++) {
493 if (addressGroups[i].equals("")) {
494 for (int j = 0; j < zerosToBePushed; j++) {
499 ready[index] = addressGroups[i];
505 Arrays.fill(ready, "0");
506 ready[ready.length - 1] = addressGroups[addressGroups.length - 1];
509 throw new IllegalStateException("Incorrect ipv6 address");
515 * Computes length of match (in bytes)
517 * @return length of ofp_match (excluding padding)
519 public static int computeMatchLengthInternal(Match match) {
522 length += MATCH_TYPE_AND_LENGTH_SIZE + computeMatchEntriesLength(match.getMatchEntries());
528 * Computes length of match (in bytes)
530 * @return length of ofp_match (excluding padding)
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;
542 * Computes length of MatchEntries (in bytes)
543 * @param matchEntries list of match entries (oxm_fields)
544 * @return length of MatchEntries
546 public static int computeMatchEntriesLength(List<MatchEntries> matchEntries) {
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);
638 private static int computePossibleMaskEntryLength(MatchEntries entry, int length) {
639 int entryLength = length;
640 if (entry.isHasMask()) {