1 /* Copyright (C)2013 Pantheon Technologies, s.r.o. All rights reserved. */
\r
2 package org.opendaylight.openflowjava.protocol.impl.util;
\r
4 import io.netty.buffer.ByteBuf;
\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
11 import org.opendaylight.openflowjava.protocol.impl.serialization.factories.EncodeConstants;
\r
12 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.BosMatchEntry;
\r
13 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.DscpMatchEntry;
\r
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.EcnMatchEntry;
\r
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.EthTypeMatchEntry;
\r
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv4CodeMatchEntry;
\r
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv4TypeMatchEntry;
\r
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv6CodeMatchEntry;
\r
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv6TypeMatchEntry;
\r
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Ipv4AddressMatchEntry;
\r
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Ipv6AddressMatchEntry;
\r
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Ipv6FlabelMatchEntry;
\r
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.IsidMatchEntry;
\r
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MacAddressMatchEntry;
\r
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MaskMatchEntry;
\r
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MetadataMatchEntry;
\r
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MplsLabelMatchEntry;
\r
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.OpCodeMatchEntry;
\r
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PortMatchEntry;
\r
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PortNumberMatchEntry;
\r
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ProtocolNumberMatchEntry;
\r
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PseudoFieldMatchEntry;
\r
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PseudoFieldMatchEntry.PseudoField;
\r
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.TcMatchEntry;
\r
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.VlanPcpMatchEntry;
\r
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.VlanVidMatchEntry;
\r
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.StandardMatchType;
\r
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpOp;
\r
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpSha;
\r
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpSpa;
\r
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpTha;
\r
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpTpa;
\r
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Clazz;
\r
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.EthDst;
\r
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.EthSrc;
\r
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.EthType;
\r
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ExperimenterClass;
\r
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv4Code;
\r
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv4Type;
\r
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv6Code;
\r
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv6Type;
\r
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.InPhyPort;
\r
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.InPort;
\r
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.IpDscp;
\r
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.IpEcn;
\r
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.IpProto;
\r
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv4Dst;
\r
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv4Src;
\r
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Dst;
\r
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Exthdr;
\r
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Flabel;
\r
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6NdSll;
\r
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6NdTarget;
\r
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6NdTll;
\r
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Src;
\r
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MatchField;
\r
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Metadata;
\r
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MplsBos;
\r
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MplsLabel;
\r
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MplsTc;
\r
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Nxm0Class;
\r
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Nxm1Class;
\r
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.OpenflowBasicClass;
\r
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.OxmMatchType;
\r
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.PbbIsid;
\r
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.SctpDst;
\r
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.SctpSrc;
\r
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.TcpDst;
\r
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.TcpSrc;
\r
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.TunnelId;
\r
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.UdpDst;
\r
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.UdpSrc;
\r
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.VlanPcp;
\r
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.VlanVid;
\r
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.oxm.fields.MatchEntries;
\r
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.match.grouping.Match;
\r
87 import org.slf4j.Logger;
\r
88 import org.slf4j.LoggerFactory;
\r
91 * @author michal.polkorab
\r
94 public class MatchSerializer {
\r
96 private static final Logger LOGGER = LoggerFactory.getLogger(MatchSerializer.class);
\r
100 * @param match ofp_match object
\r
101 * @param out output ByteBuf
\r
103 public static void encodeMatch(Match match, ByteBuf out) {
\r
104 if (match == null) {
\r
105 LOGGER.debug("Match is null");
\r
108 encodeType(match, out);
\r
109 // Length of ofp_match (excluding padding)
\r
110 int length = computeMatchLength(match);
\r
111 out.writeShort(length);
\r
112 encodeMatchEntries(match.getMatchEntries(), out);
\r
113 int paddingRemainder = length % EncodeConstants.PADDING;
\r
114 if (paddingRemainder != 0) {
\r
115 ByteBufUtils.padBuffer(EncodeConstants.PADDING - paddingRemainder, out);
\r
119 private static void encodeType(Match match, ByteBuf out) {
\r
120 final byte STANDARD_MATCH_TYPE_CODE = 0;
\r
121 final byte OXM_MATCH_TYPE_CODE = 1;
\r
122 if (match.getType().equals(StandardMatchType.class)) {
\r
123 out.writeShort(STANDARD_MATCH_TYPE_CODE);
\r
124 } else if (match.getType().equals(OxmMatchType.class)) {
\r
125 out.writeShort(OXM_MATCH_TYPE_CODE);
\r
130 * Encodes MatchEntries
\r
131 * @param matchEntries
\r
134 public static void encodeMatchEntries(List<MatchEntries> matchEntries, ByteBuf out) {
\r
135 if (matchEntries == null) {
\r
136 LOGGER.warn("Match entries are null");
\r
139 for (MatchEntries entry : matchEntries) {
\r
140 encodeClass(entry.getOxmClass(), out);
\r
141 encodeRest(entry, null);
\r
145 private static void encodeClass(Class<? extends Clazz> clazz, ByteBuf out) {
\r
146 final int NXM0_CLASS_CODE = 0x0000;
\r
147 final int NXM1_CLASS_CODE = 0x0001;
\r
148 final int OPENFLOW_BASIC_CLASS_CODE = 0x8000;
\r
149 final int EXPERIMENTER_CLASS_CODE = 0xFFFF;
\r
150 if (Nxm0Class.class.equals(clazz)) {
\r
151 out.writeShort(NXM0_CLASS_CODE);
\r
152 } else if (Nxm1Class.class.equals(clazz)) {
\r
153 out.writeShort(NXM1_CLASS_CODE);
\r
154 } else if (OpenflowBasicClass.class.equals(clazz)) {
\r
155 out.writeShort(OPENFLOW_BASIC_CLASS_CODE);
\r
156 } else if (ExperimenterClass.class.equals(clazz)) {
\r
157 out.writeShort(EXPERIMENTER_CLASS_CODE);
\r
161 private static void encodeRest(MatchEntries entry, ByteBuf out) {
\r
162 int fieldValue = 0;
\r
163 Class<? extends MatchField> field = entry.getOxmMatchField();
\r
164 if (field.equals(InPort.class)) {
\r
166 writeOxmFieldAndLength(out, fieldValue, Integer.SIZE / Byte.SIZE);
\r
167 out.writeInt(entry.getAugmentation(PortNumberMatchEntry.class).getPortNumber().getValue().intValue());
\r
168 } else if (field.equals(InPhyPort.class)) {
\r
170 writeOxmFieldAndLength(out, fieldValue, Integer.SIZE / Byte.SIZE);
\r
171 out.writeInt(entry.getAugmentation(PortNumberMatchEntry.class).getPortNumber().getValue().intValue());
\r
172 } else if (field.equals(Metadata.class)) {
\r
174 writeMetadataRelatedEntry(entry, out, fieldValue);
\r
175 } else if (field.equals(EthDst.class)) {
\r
177 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
178 } else if (field.equals(EthSrc.class)) {
\r
180 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
181 } else if (field.equals(EthType.class)) {
\r
183 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
184 out.writeShort(entry.getAugmentation(EthTypeMatchEntry.class).getEthType().getValue().shortValue());
\r
185 } else if (field.equals(VlanVid.class)) {
\r
187 fieldValue = fieldValue << 1;
\r
188 VlanVidMatchEntry vlanVid = entry.getAugmentation(VlanVidMatchEntry.class);
\r
189 int vlanVidValue = vlanVid.getVlanVid() << 1;
\r
190 if (vlanVid.isCfiBit()) {
\r
191 vlanVidValue = vlanVidValue | 1;
\r
193 if (entry.isHasMask()) {
\r
194 fieldValue = fieldValue | 1;
\r
195 out.writeByte(fieldValue);
\r
196 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
197 out.writeByte(Short.SIZE / Byte.SIZE + mask.length);
\r
198 out.writeShort(vlanVidValue);
\r
199 out.writeBytes(mask);
\r
201 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
202 out.writeShort(vlanVidValue);
\r
204 } else if (field.equals(VlanPcp.class)) {
\r
206 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
207 out.writeByte(entry.getAugmentation(VlanPcpMatchEntry.class).getVlanPcp().byteValue());
\r
208 } else if (field.equals(IpDscp.class)) {
\r
210 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
211 out.writeByte(entry.getAugmentation(DscpMatchEntry.class).getDscp().getValue());
\r
212 } else if (field.equals(IpEcn.class)) {
\r
214 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
215 out.writeByte(entry.getAugmentation(EcnMatchEntry.class).getEcn());
\r
216 } else if (field.equals(IpProto.class)) {
\r
218 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
219 out.writeByte(entry.getAugmentation(ProtocolNumberMatchEntry.class).getProtocolNumber());
\r
220 } else if (field.equals(Ipv4Src.class)) {
\r
222 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
\r
223 } else if (field.equals(Ipv4Dst.class)) {
\r
225 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
\r
226 } else if (field.equals(TcpSrc.class)) {
\r
228 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
229 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
230 } else if (field.equals(TcpDst.class)) {
\r
232 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
233 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
234 } else if (field.equals(UdpSrc.class)) {
\r
236 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
237 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
238 } else if (field.equals(UdpDst.class)) {
\r
240 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
241 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
242 } else if (field.equals(SctpSrc.class)) {
\r
244 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
245 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
246 } else if (field.equals(SctpDst.class)) {
\r
248 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
249 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
250 } else if (field.equals(Icmpv4Type.class)) {
\r
252 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
253 out.writeByte(entry.getAugmentation(Icmpv4TypeMatchEntry.class).getIcmpv4Type());
\r
254 } else if (field.equals(Icmpv4Code.class)) {
\r
256 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
257 out.writeByte(entry.getAugmentation(Icmpv4CodeMatchEntry.class).getIcmpv4Code());
\r
258 } else if (field.equals(ArpOp.class)) {
\r
260 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
261 out.writeShort(entry.getAugmentation(OpCodeMatchEntry.class).getOpCode());
\r
262 } else if (field.equals(ArpSpa.class)) {
\r
264 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
\r
265 } else if (field.equals(ArpTpa.class)) {
\r
267 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
\r
268 } else if (field.equals(ArpSha.class)) {
\r
270 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
271 } else if (field.equals(ArpTha.class)) {
\r
273 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
274 } else if (field.equals(Ipv6Src.class)) {
\r
276 writeIpv6AddressRelatedEntry(entry, out, fieldValue);
\r
277 } else if (field.equals(Ipv6Dst.class)) {
\r
279 writeIpv6AddressRelatedEntry(entry, out, fieldValue);
\r
280 } else if (field.equals(Ipv6Flabel.class)) {
\r
282 fieldValue = fieldValue << 1;
\r
283 if (entry.isHasMask()) {
\r
284 fieldValue = fieldValue | 1;
\r
285 out.writeByte(fieldValue);
\r
286 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
287 out.writeByte(Integer.SIZE / Byte.SIZE + mask.length); // 20 b + mask [OF 1.3.2 spec]
\r
288 LOGGER.warn("Ipv6Flabel match entry: possible wrong length written (wrote 4 - maybe must be 3)");
\r
289 out.writeInt(entry.getAugmentation(Ipv6FlabelMatchEntry.class).getIpv6Flabel().getValue().intValue());
\r
290 out.writeBytes(entry.getAugmentation(MaskMatchEntry.class).getMask());
\r
292 out.writeByte(fieldValue);
\r
293 out.writeByte(Integer.SIZE / Byte.SIZE); // 20 b [OF 1.3.2 spec]
\r
294 LOGGER.warn("Ipv6Flabel match entry: possible wrong length written (wrote 4 - maybe must be 3)");
\r
295 out.writeInt(entry.getAugmentation(Ipv6FlabelMatchEntry.class).getIpv6Flabel().getValue().intValue());
\r
297 } else if (field.equals(Icmpv6Type.class)) {
\r
299 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
300 out.writeByte(entry.getAugmentation(Icmpv6TypeMatchEntry.class).getIcmpv6Type());
\r
301 } else if (field.equals(Icmpv6Code.class)) {
\r
303 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
304 out.writeByte(entry.getAugmentation(Icmpv6CodeMatchEntry.class).getIcmpv6Code());
\r
305 } else if (field.equals(Ipv6NdTarget.class)) {
\r
307 writeIpv6AddressRelatedEntry(entry, out, fieldValue);
\r
308 } else if (field.equals(Ipv6NdSll.class)) {
\r
310 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
311 } else if (field.equals(Ipv6NdTll.class)) {
\r
313 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
314 } else if (field.equals(MplsLabel.class)) {
\r
316 writeOxmFieldAndLength(out, fieldValue, Integer.SIZE / Byte.SIZE);
\r
317 LOGGER.warn("MplsLabel match entry: possible wrong length written (wrote 4 - maybe must be 3)");
\r
318 out.writeInt(entry.getAugmentation(MplsLabelMatchEntry.class).getMplsLabel().intValue());
\r
319 } else if (field.equals(MplsTc.class)) {
\r
321 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
322 out.writeByte(entry.getAugmentation(TcMatchEntry.class).getTc());
\r
323 } else if (field.equals(MplsBos.class)) {
\r
325 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
326 out.writeBoolean(entry.getAugmentation(BosMatchEntry.class).isBos().booleanValue());
\r
327 } else if (field.equals(PbbIsid.class)) {
\r
329 fieldValue = fieldValue << 1;
\r
330 if (entry.isHasMask()) {
\r
331 fieldValue = fieldValue | 1;
\r
332 out.writeByte(fieldValue);
\r
333 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
334 out.writeByte(Long.SIZE / Byte.SIZE + mask.length);
\r
335 LOGGER.warn("PbbIsid match entry: possible wrong length written (wrote 4 - maybe must be 3)");
\r
336 out.writeInt(entry.getAugmentation(IsidMatchEntry.class).getIsid().intValue());
\r
337 out.writeBytes(mask);
\r
339 out.writeByte(fieldValue);
\r
340 out.writeByte(Long.SIZE / Byte.SIZE);
\r
341 LOGGER.warn("PbbIsid match entry: possible wrong length written (wrote 4 - maybe must be 3)");
\r
342 out.writeInt(entry.getAugmentation(IsidMatchEntry.class).getIsid().intValue());
\r
344 } else if (field.equals(TunnelId.class)) {
\r
346 writeMetadataRelatedEntry(entry, out, fieldValue);
\r
347 } else if (field.equals(Ipv6Exthdr.class)) {
\r
349 fieldValue = fieldValue << 1;
\r
350 PseudoField pseudoField = entry.getAugmentation(PseudoFieldMatchEntry.class).getPseudoField();
\r
351 Map<Integer, Boolean> map = new HashMap<>();
\r
352 map.put(0, pseudoField.isNonext());
\r
353 map.put(1, pseudoField.isEsp());
\r
354 map.put(2, pseudoField.isAuth());
\r
355 map.put(3, pseudoField.isDest());
\r
356 map.put(4, pseudoField.isFrag());
\r
357 map.put(5, pseudoField.isRouter());
\r
358 map.put(6, pseudoField.isHop());
\r
359 map.put(7, pseudoField.isUnrep());
\r
360 map.put(8, pseudoField.isUnseq());
\r
361 int bitmap = ByteBufUtils.fillBitMaskFromMap(map);
\r
362 if (entry.isHasMask()) {
\r
363 fieldValue = fieldValue | 1;
\r
364 out.writeByte(fieldValue);
\r
365 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
366 out.writeByte(Short.SIZE / Byte.SIZE + mask.length);
\r
367 out.writeShort(bitmap);
\r
368 out.writeBytes(mask);
\r
370 out.writeByte(fieldValue);
\r
371 out.writeByte(Short.SIZE / Byte.SIZE);
\r
372 out.writeShort(bitmap);
\r
377 private static void writeOxmFieldAndLength(ByteBuf out, int fieldValue, int length) {
\r
378 int fieldAndMask = fieldValue << 1;
\r
379 out.writeByte(fieldAndMask);
\r
380 out.writeByte(length);
\r
383 private static void writeMetadataRelatedEntry(MatchEntries entry, ByteBuf out, int value) {
\r
384 int fieldValue = value << 1;
\r
385 if (entry.isHasMask()) {
\r
386 fieldValue = fieldValue | 1;
\r
387 out.writeByte(fieldValue);
\r
388 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
389 out.writeByte(Long.SIZE / Byte.SIZE + mask.length);
\r
390 out.writeBytes(entry.getAugmentation(MetadataMatchEntry.class).getMetadata());
\r
391 out.writeBytes(mask);
\r
393 out.writeByte(fieldValue);
\r
394 out.writeByte(Long.SIZE / Byte.SIZE);
\r
395 out.writeBytes(entry.getAugmentation(MetadataMatchEntry.class).getMetadata());
\r
399 private static void writeMacAddressRelatedEntry(MatchEntries entry, ByteBuf out, int value) {
\r
400 int fieldValue = value << 1;
\r
401 if (entry.isHasMask()) {
\r
402 fieldValue = fieldValue | 1;
\r
403 out.writeByte(fieldValue);
\r
404 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
405 out.writeByte((Integer.SIZE + Short.SIZE) / Byte.SIZE + mask.length); // 48 b + mask [OF 1.3.2 spec]
\r
406 out.writeBytes(entry.getAugmentation(MacAddressMatchEntry.class).getMacAddress().getValue().getBytes());
\r
407 out.writeBytes(mask);
\r
409 out.writeByte(fieldValue);
\r
410 out.writeByte((Integer.SIZE + Short.SIZE) / Byte.SIZE); // 48 b [OF 1.3.2 spec]
\r
411 out.writeBytes(entry.getAugmentation(MacAddressMatchEntry.class).getMacAddress().getValue().getBytes());
\r
415 private static void writeIpv4AddressRelatedEntry(MatchEntries entry, ByteBuf out, int value) {
\r
416 int fieldValue = value << 1;
\r
417 if (entry.isHasMask()) {
\r
418 fieldValue = fieldValue | 1;
\r
419 out.writeByte(fieldValue);
\r
420 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
421 out.writeByte(Integer.SIZE / Byte.SIZE + mask.length);
\r
422 writeIpv4Address(entry, out);
\r
423 out.writeBytes(mask);
\r
425 out.writeByte(fieldValue);
\r
426 out.writeByte(Integer.SIZE / Byte.SIZE);
\r
427 writeIpv4Address(entry, out);
\r
431 private static void writeIpv4Address(MatchEntries entry, ByteBuf out) {
\r
432 String[] addressGroups = entry.getAugmentation(Ipv4AddressMatchEntry.class).getIpv4Address().getValue().split(".");
\r
433 for (int i = 0; i < addressGroups.length; i++) {
\r
434 out.writeByte(Integer.parseInt(addressGroups[i]));
\r
438 private static void writeIpv6AddressRelatedEntry(MatchEntries entry, ByteBuf out, int value) {
\r
439 int fieldValue = value << 1;
\r
440 String[] addressGroups = entry.getAugmentation(Ipv6AddressMatchEntry.class).getIpv6Address().getValue().split(":");
\r
441 String[] address = parseIpv6Address(addressGroups);
\r
442 if (entry.isHasMask()) {
\r
443 fieldValue = fieldValue | 1;
\r
444 out.writeByte(fieldValue);
\r
445 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
446 out.writeByte((8 * Short.SIZE) / Byte.SIZE + mask.length);
\r
447 for (int i = 0; i < address.length; i++) {
\r
448 out.writeShort(Integer.parseInt(addressGroups[i], 16));
\r
450 out.writeBytes(mask);
\r
452 out.writeByte(fieldValue);
\r
453 out.writeByte((8 * Short.SIZE) / Byte.SIZE);
\r
454 for (int i = 0; i < addressGroups.length; i++) {
\r
455 out.writeShort(Integer.parseInt(addressGroups[i], 16));
\r
460 private static String[] parseIpv6Address(String[] addressGroups) {
\r
461 final byte GROUPS_IN_IPV6_ADDRESS = 8;
\r
462 int countEmpty = 0;
\r
463 for (int i = 0; i < addressGroups.length; i++) {
\r
464 if (addressGroups[i].equals("")){
\r
468 String[] ready = new String[GROUPS_IN_IPV6_ADDRESS];
\r
469 switch (countEmpty) {
\r
471 ready = addressGroups;
\r
474 int zerosToBePushed = GROUPS_IN_IPV6_ADDRESS - addressGroups.length + 1;
\r
476 for (int i = 0; i < addressGroups.length; i++) {
\r
477 if (addressGroups[i].equals("")) {
\r
478 for (int j = 0; j < zerosToBePushed; j++) {
\r
483 ready[i + pushed] = addressGroups[i];
\r
488 Arrays.fill(ready, "0");
\r
489 ready[ready.length - 1] = addressGroups[addressGroups.length - 1];
\r
492 Arrays.fill(ready, "0");
\r
502 * Computes length of ofp_match structure (in bytes)
\r
504 * @return length of ofp_match (excluding padding)
\r
506 public static int computeMatchLength(Match match) {
\r
507 final byte MATCH_TYPE_AND_LENGTH_SIZE = 4;
\r
509 if (match != null) {
\r
510 length += MATCH_TYPE_AND_LENGTH_SIZE + computeMatchEntriesLength(match.getMatchEntries());
\r
516 * Computes length of MatchEntries (in bytes)
\r
517 * @param matchEntries
\r
518 * @return length of MatchEntries
\r
520 public static int computeMatchEntriesLength(List<MatchEntries> matchEntries) {
\r
521 final byte MATCH_ENTRY_HEADER_LENGTH = 4;
\r
523 if (matchEntries != null) {
\r
524 for (MatchEntries entry : matchEntries) {
\r
525 length += MATCH_ENTRY_HEADER_LENGTH;
\r
526 Class<? extends MatchField> field = entry.getOxmMatchField();
\r
527 if (field.equals(InPort.class)) {
\r
528 length += Integer.SIZE / Byte.SIZE;
\r
529 } else if (field.equals(InPhyPort.class)) {
\r
530 length += Integer.SIZE / Byte.SIZE;
\r
531 } else if (field.equals(Metadata.class)) {
\r
532 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
533 } else if (field.equals(EthDst.class)) {
\r
534 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
535 } else if (field.equals(EthSrc.class)) {
\r
536 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
537 } else if (field.equals(EthType.class)) {
\r
538 length += Short.SIZE / Byte.SIZE;
\r
539 } else if (field.equals(VlanVid.class)) {
\r
540 length += computePossibleMaskEntryLength(entry, Short.SIZE / Byte.SIZE);
\r
541 } else if (field.equals(VlanPcp.class)) {
\r
542 length += Byte.SIZE / Byte.SIZE;
\r
543 } else if (field.equals(IpDscp.class)) {
\r
544 length += Byte.SIZE / Byte.SIZE;
\r
545 } else if (field.equals(IpEcn.class)) {
\r
546 length += Byte.SIZE / Byte.SIZE;
\r
547 } else if (field.equals(IpProto.class)) {
\r
548 length += Byte.SIZE / Byte.SIZE;
\r
549 } else if (field.equals(Ipv4Src.class)) {
\r
550 length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);
\r
551 } else if (field.equals(Ipv4Dst.class)) {
\r
552 length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);
\r
553 } else if (field.equals(TcpSrc.class)) {
\r
554 length += Short.SIZE / Byte.SIZE;
\r
555 } else if (field.equals(TcpDst.class)) {
\r
556 length += Short.SIZE / Byte.SIZE;
\r
557 } else if (field.equals(UdpSrc.class)) {
\r
558 length += Short.SIZE / Byte.SIZE;
\r
559 } else if (field.equals(UdpDst.class)) {
\r
560 length += Short.SIZE / Byte.SIZE;
\r
561 } else if (field.equals(SctpSrc.class)) {
\r
562 length += Short.SIZE / Byte.SIZE;
\r
563 } else if (field.equals(SctpDst.class)) {
\r
564 length += Short.SIZE / Byte.SIZE;
\r
565 } else if (field.equals(Icmpv4Type.class)) {
\r
566 length += Byte.SIZE / Byte.SIZE;
\r
567 } else if (field.equals(Icmpv4Code.class)) {
\r
568 length += Byte.SIZE / Byte.SIZE;
\r
569 } else if (field.equals(ArpOp.class)) {
\r
570 length += Short.SIZE / Byte.SIZE;
\r
571 } else if (field.equals(ArpSpa.class)) {
\r
572 length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);
\r
573 } else if (field.equals(ArpTpa.class)) {
\r
574 length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);
\r
575 } else if (field.equals(ArpSha.class)) {
\r
576 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
577 } else if (field.equals(ArpTha.class)) {
\r
578 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
579 } else if (field.equals(Ipv6Src.class)) {
\r
580 length += computePossibleMaskEntryLength(entry, 8 * (Short.SIZE / Byte.SIZE));
\r
581 } else if (field.equals(Ipv6Dst.class)) {
\r
582 length += computePossibleMaskEntryLength(entry, 8 * (Short.SIZE / Byte.SIZE));
\r
583 } else if (field.equals(Ipv6Flabel.class)) {
\r
584 length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);
\r
585 } else if (field.equals(Icmpv6Type.class)) {
\r
586 length += Byte.SIZE / Byte.SIZE;
\r
587 } else if (field.equals(Icmpv6Code.class)) {
\r
588 length += Byte.SIZE / Byte.SIZE;
\r
589 } else if (field.equals(Ipv6NdTarget.class)) {
\r
590 length += computePossibleMaskEntryLength(entry, 8 * (Short.SIZE / Byte.SIZE));
\r
591 } else if (field.equals(Ipv6NdSll.class)) {
\r
592 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
593 } else if (field.equals(Ipv6NdTll.class)) {
\r
594 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
595 } else if (field.equals(MplsLabel.class)) {
\r
596 length += Integer.SIZE / Byte.SIZE;
\r
597 } else if (field.equals(MplsTc.class)) {
\r
598 length += Byte.SIZE / Byte.SIZE;
\r
599 } else if (field.equals(MplsBos.class)) {
\r
600 length += Byte.SIZE / Byte.SIZE;
\r
601 } else if (field.equals(PbbIsid.class)) {
\r
602 length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);
\r
603 } else if (field.equals(TunnelId.class)) {
\r
604 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
605 } else if (field.equals(Ipv6Exthdr.class)) {
\r
606 length += computePossibleMaskEntryLength(entry, Short.SIZE / Byte.SIZE);
\r
613 private static int computePossibleMaskEntryLength(MatchEntries entry, int length) {
\r
614 int entryLength = length;
\r
615 if (entry.isHasMask()) {
\r
618 return entryLength;
\r