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 * Serializes ofp_match (OpenFlow v1.3) and its oxm_fields structures
\r
92 * @author michal.polkorab
\r
93 * @author timotej.kubas
\r
95 public class MatchSerializer {
\r
97 private static final Logger LOGGER = LoggerFactory.getLogger(MatchSerializer.class);
\r
100 * Encodes match (OpenFlow v1.3)
\r
101 * @param match ofp_match object
\r
102 * @param out output ByteBuf
\r
104 public static void encodeMatch(Match match, ByteBuf out) {
\r
105 if (match == null) {
\r
106 LOGGER.debug("Match is null");
\r
109 encodeType(match, out);
\r
110 // Length of ofp_match (excluding padding)
\r
111 int length = computeMatchLength(match);
\r
112 out.writeShort(length);
\r
113 encodeMatchEntries(match.getMatchEntries(), out);
\r
114 int paddingRemainder = length % EncodeConstants.PADDING;
\r
115 if (paddingRemainder != 0) {
\r
116 ByteBufUtils.padBuffer(EncodeConstants.PADDING - paddingRemainder, out);
\r
120 private static void encodeType(Match match, ByteBuf out) {
\r
121 final byte STANDARD_MATCH_TYPE_CODE = 0;
\r
122 final byte OXM_MATCH_TYPE_CODE = 1;
\r
123 if (match.getType().equals(StandardMatchType.class)) {
\r
124 out.writeShort(STANDARD_MATCH_TYPE_CODE);
\r
125 } else if (match.getType().equals(OxmMatchType.class)) {
\r
126 out.writeShort(OXM_MATCH_TYPE_CODE);
\r
131 * Encodes MatchEntries
\r
132 * @param matchEntries list of match entries (oxm_fields)
\r
133 * @param out output ByteBuf
\r
135 public static void encodeMatchEntries(List<MatchEntries> matchEntries, ByteBuf out) {
\r
136 if (matchEntries == null) {
\r
137 LOGGER.warn("Match entries are null");
\r
140 for (MatchEntries entry : matchEntries) {
\r
141 encodeClass(entry.getOxmClass(), out);
\r
142 encodeRest(entry, null);
\r
146 private static void encodeClass(Class<? extends Clazz> clazz, ByteBuf out) {
\r
147 final int NXM0_CLASS_CODE = 0x0000;
\r
148 final int NXM1_CLASS_CODE = 0x0001;
\r
149 final int OPENFLOW_BASIC_CLASS_CODE = 0x8000;
\r
150 final int EXPERIMENTER_CLASS_CODE = 0xFFFF;
\r
151 if (Nxm0Class.class.equals(clazz)) {
\r
152 out.writeShort(NXM0_CLASS_CODE);
\r
153 } else if (Nxm1Class.class.equals(clazz)) {
\r
154 out.writeShort(NXM1_CLASS_CODE);
\r
155 } else if (OpenflowBasicClass.class.equals(clazz)) {
\r
156 out.writeShort(OPENFLOW_BASIC_CLASS_CODE);
\r
157 } else if (ExperimenterClass.class.equals(clazz)) {
\r
158 out.writeShort(EXPERIMENTER_CLASS_CODE);
\r
162 private static void encodeRest(MatchEntries entry, ByteBuf out) {
\r
163 int fieldValue = 0;
\r
164 Class<? extends MatchField> field = entry.getOxmMatchField();
\r
165 if (field.equals(InPort.class)) {
\r
167 writeOxmFieldAndLength(out, fieldValue, Integer.SIZE / Byte.SIZE);
\r
168 out.writeInt(entry.getAugmentation(PortNumberMatchEntry.class).getPortNumber().getValue().intValue());
\r
169 } else if (field.equals(InPhyPort.class)) {
\r
171 writeOxmFieldAndLength(out, fieldValue, Integer.SIZE / Byte.SIZE);
\r
172 out.writeInt(entry.getAugmentation(PortNumberMatchEntry.class).getPortNumber().getValue().intValue());
\r
173 } else if (field.equals(Metadata.class)) {
\r
175 writeMetadataRelatedEntry(entry, out, fieldValue);
\r
176 } else if (field.equals(EthDst.class)) {
\r
178 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
179 } else if (field.equals(EthSrc.class)) {
\r
181 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
182 } else if (field.equals(EthType.class)) {
\r
184 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
185 out.writeShort(entry.getAugmentation(EthTypeMatchEntry.class).getEthType().getValue().shortValue());
\r
186 } else if (field.equals(VlanVid.class)) {
\r
188 fieldValue = fieldValue << 1;
\r
189 VlanVidMatchEntry vlanVid = entry.getAugmentation(VlanVidMatchEntry.class);
\r
190 int vlanVidValue = vlanVid.getVlanVid() << 1;
\r
191 if (vlanVid.isCfiBit()) {
\r
192 vlanVidValue = vlanVidValue | 1;
\r
194 if (entry.isHasMask()) {
\r
195 fieldValue = fieldValue | 1;
\r
196 out.writeByte(fieldValue);
\r
197 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
198 out.writeByte(Short.SIZE / Byte.SIZE + mask.length);
\r
199 out.writeShort(vlanVidValue);
\r
200 out.writeBytes(mask);
\r
202 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
203 out.writeShort(vlanVidValue);
\r
205 } else if (field.equals(VlanPcp.class)) {
\r
207 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
208 out.writeByte(entry.getAugmentation(VlanPcpMatchEntry.class).getVlanPcp().byteValue());
\r
209 } else if (field.equals(IpDscp.class)) {
\r
211 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
212 out.writeByte(entry.getAugmentation(DscpMatchEntry.class).getDscp().getValue());
\r
213 } else if (field.equals(IpEcn.class)) {
\r
215 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
216 out.writeByte(entry.getAugmentation(EcnMatchEntry.class).getEcn());
\r
217 } else if (field.equals(IpProto.class)) {
\r
219 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
220 out.writeByte(entry.getAugmentation(ProtocolNumberMatchEntry.class).getProtocolNumber());
\r
221 } else if (field.equals(Ipv4Src.class)) {
\r
223 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
\r
224 } else if (field.equals(Ipv4Dst.class)) {
\r
226 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
\r
227 } else if (field.equals(TcpSrc.class)) {
\r
229 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
230 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
231 } else if (field.equals(TcpDst.class)) {
\r
233 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
234 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
235 } else if (field.equals(UdpSrc.class)) {
\r
237 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
238 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
239 } else if (field.equals(UdpDst.class)) {
\r
241 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
242 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
243 } else if (field.equals(SctpSrc.class)) {
\r
245 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
246 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
247 } else if (field.equals(SctpDst.class)) {
\r
249 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
250 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
251 } else if (field.equals(Icmpv4Type.class)) {
\r
253 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
254 out.writeByte(entry.getAugmentation(Icmpv4TypeMatchEntry.class).getIcmpv4Type());
\r
255 } else if (field.equals(Icmpv4Code.class)) {
\r
257 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
258 out.writeByte(entry.getAugmentation(Icmpv4CodeMatchEntry.class).getIcmpv4Code());
\r
259 } else if (field.equals(ArpOp.class)) {
\r
261 writeOxmFieldAndLength(out, fieldValue, Short.SIZE / Byte.SIZE);
\r
262 out.writeShort(entry.getAugmentation(OpCodeMatchEntry.class).getOpCode());
\r
263 } else if (field.equals(ArpSpa.class)) {
\r
265 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
\r
266 } else if (field.equals(ArpTpa.class)) {
\r
268 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
\r
269 } else if (field.equals(ArpSha.class)) {
\r
271 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
272 } else if (field.equals(ArpTha.class)) {
\r
274 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
275 } else if (field.equals(Ipv6Src.class)) {
\r
277 writeIpv6AddressRelatedEntry(entry, out, fieldValue);
\r
278 } else if (field.equals(Ipv6Dst.class)) {
\r
280 writeIpv6AddressRelatedEntry(entry, out, fieldValue);
\r
281 } else if (field.equals(Ipv6Flabel.class)) {
\r
283 fieldValue = fieldValue << 1;
\r
284 if (entry.isHasMask()) {
\r
285 fieldValue = fieldValue | 1;
\r
286 out.writeByte(fieldValue);
\r
287 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
288 out.writeByte(Integer.SIZE / Byte.SIZE + mask.length); // 20 b + mask [OF 1.3.2 spec]
\r
289 LOGGER.warn("Ipv6Flabel match entry: possible wrong length written (wrote 4 - maybe must be 3)");
\r
290 out.writeInt(entry.getAugmentation(Ipv6FlabelMatchEntry.class).getIpv6Flabel().getValue().intValue());
\r
291 out.writeBytes(entry.getAugmentation(MaskMatchEntry.class).getMask());
\r
293 out.writeByte(fieldValue);
\r
294 out.writeByte(Integer.SIZE / Byte.SIZE); // 20 b [OF 1.3.2 spec]
\r
295 LOGGER.warn("Ipv6Flabel match entry: possible wrong length written (wrote 4 - maybe must be 3)");
\r
296 out.writeInt(entry.getAugmentation(Ipv6FlabelMatchEntry.class).getIpv6Flabel().getValue().intValue());
\r
298 } else if (field.equals(Icmpv6Type.class)) {
\r
300 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
301 out.writeByte(entry.getAugmentation(Icmpv6TypeMatchEntry.class).getIcmpv6Type());
\r
302 } else if (field.equals(Icmpv6Code.class)) {
\r
304 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
305 out.writeByte(entry.getAugmentation(Icmpv6CodeMatchEntry.class).getIcmpv6Code());
\r
306 } else if (field.equals(Ipv6NdTarget.class)) {
\r
308 writeIpv6AddressRelatedEntry(entry, out, fieldValue);
\r
309 } else if (field.equals(Ipv6NdSll.class)) {
\r
311 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
312 } else if (field.equals(Ipv6NdTll.class)) {
\r
314 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
315 } else if (field.equals(MplsLabel.class)) {
\r
317 writeOxmFieldAndLength(out, fieldValue, Integer.SIZE / Byte.SIZE);
\r
318 LOGGER.warn("MplsLabel match entry: possible wrong length written (wrote 4 - maybe must be 3)");
\r
319 out.writeInt(entry.getAugmentation(MplsLabelMatchEntry.class).getMplsLabel().intValue());
\r
320 } else if (field.equals(MplsTc.class)) {
\r
322 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
323 out.writeByte(entry.getAugmentation(TcMatchEntry.class).getTc());
\r
324 } else if (field.equals(MplsBos.class)) {
\r
326 writeOxmFieldAndLength(out, fieldValue, Byte.SIZE / Byte.SIZE);
\r
327 out.writeBoolean(entry.getAugmentation(BosMatchEntry.class).isBos().booleanValue());
\r
328 } else if (field.equals(PbbIsid.class)) {
\r
330 fieldValue = fieldValue << 1;
\r
331 if (entry.isHasMask()) {
\r
332 fieldValue = fieldValue | 1;
\r
333 out.writeByte(fieldValue);
\r
334 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
335 out.writeByte(Long.SIZE / Byte.SIZE + mask.length);
\r
336 LOGGER.warn("PbbIsid match entry: possible wrong length written (wrote 4 - maybe must be 3)");
\r
337 out.writeInt(entry.getAugmentation(IsidMatchEntry.class).getIsid().intValue());
\r
338 out.writeBytes(mask);
\r
340 out.writeByte(fieldValue);
\r
341 out.writeByte(Long.SIZE / Byte.SIZE);
\r
342 LOGGER.warn("PbbIsid match entry: possible wrong length written (wrote 4 - maybe must be 3)");
\r
343 out.writeInt(entry.getAugmentation(IsidMatchEntry.class).getIsid().intValue());
\r
345 } else if (field.equals(TunnelId.class)) {
\r
347 writeMetadataRelatedEntry(entry, out, fieldValue);
\r
348 } else if (field.equals(Ipv6Exthdr.class)) {
\r
350 fieldValue = fieldValue << 1;
\r
351 PseudoField pseudoField = entry.getAugmentation(PseudoFieldMatchEntry.class).getPseudoField();
\r
352 Map<Integer, Boolean> map = new HashMap<>();
\r
353 map.put(0, pseudoField.isNonext());
\r
354 map.put(1, pseudoField.isEsp());
\r
355 map.put(2, pseudoField.isAuth());
\r
356 map.put(3, pseudoField.isDest());
\r
357 map.put(4, pseudoField.isFrag());
\r
358 map.put(5, pseudoField.isRouter());
\r
359 map.put(6, pseudoField.isHop());
\r
360 map.put(7, pseudoField.isUnrep());
\r
361 map.put(8, pseudoField.isUnseq());
\r
362 int bitmap = ByteBufUtils.fillBitMaskFromMap(map);
\r
363 if (entry.isHasMask()) {
\r
364 fieldValue = fieldValue | 1;
\r
365 out.writeByte(fieldValue);
\r
366 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
367 out.writeByte(Short.SIZE / Byte.SIZE + mask.length);
\r
368 out.writeShort(bitmap);
\r
369 out.writeBytes(mask);
\r
371 out.writeByte(fieldValue);
\r
372 out.writeByte(Short.SIZE / Byte.SIZE);
\r
373 out.writeShort(bitmap);
\r
378 private static void writeOxmFieldAndLength(ByteBuf out, int fieldValue, int length) {
\r
379 int fieldAndMask = fieldValue << 1;
\r
380 out.writeByte(fieldAndMask);
\r
381 out.writeByte(length);
\r
384 private static void writeMetadataRelatedEntry(MatchEntries entry, ByteBuf out, int value) {
\r
385 int fieldValue = value << 1;
\r
386 if (entry.isHasMask()) {
\r
387 fieldValue = fieldValue | 1;
\r
388 out.writeByte(fieldValue);
\r
389 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
390 out.writeByte(Long.SIZE / Byte.SIZE + mask.length);
\r
391 out.writeBytes(entry.getAugmentation(MetadataMatchEntry.class).getMetadata());
\r
392 out.writeBytes(mask);
\r
394 out.writeByte(fieldValue);
\r
395 out.writeByte(Long.SIZE / Byte.SIZE);
\r
396 out.writeBytes(entry.getAugmentation(MetadataMatchEntry.class).getMetadata());
\r
400 private static void writeMacAddressRelatedEntry(MatchEntries entry, ByteBuf out, int value) {
\r
401 int fieldValue = value << 1;
\r
402 if (entry.isHasMask()) {
\r
403 fieldValue = fieldValue | 1;
\r
404 out.writeByte(fieldValue);
\r
405 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
406 out.writeByte((Integer.SIZE + Short.SIZE) / Byte.SIZE + mask.length); // 48 b + mask [OF 1.3.2 spec]
\r
407 out.writeBytes(entry.getAugmentation(MacAddressMatchEntry.class).getMacAddress().getValue().getBytes());
\r
408 out.writeBytes(mask);
\r
410 out.writeByte(fieldValue);
\r
411 out.writeByte((Integer.SIZE + Short.SIZE) / Byte.SIZE); // 48 b [OF 1.3.2 spec]
\r
412 out.writeBytes(entry.getAugmentation(MacAddressMatchEntry.class).getMacAddress().getValue().getBytes());
\r
416 private static void writeIpv4AddressRelatedEntry(MatchEntries entry, ByteBuf out, int value) {
\r
417 int fieldValue = value << 1;
\r
418 if (entry.isHasMask()) {
\r
419 fieldValue = fieldValue | 1;
\r
420 out.writeByte(fieldValue);
\r
421 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
422 out.writeByte(Integer.SIZE / Byte.SIZE + mask.length);
\r
423 writeIpv4Address(entry, out);
\r
424 out.writeBytes(mask);
\r
426 out.writeByte(fieldValue);
\r
427 out.writeByte(Integer.SIZE / Byte.SIZE);
\r
428 writeIpv4Address(entry, out);
\r
432 private static void writeIpv4Address(MatchEntries entry, ByteBuf out) {
\r
433 String[] addressGroups = entry.getAugmentation(Ipv4AddressMatchEntry.class).getIpv4Address().getValue().split(".");
\r
434 for (int i = 0; i < addressGroups.length; i++) {
\r
435 out.writeByte(Integer.parseInt(addressGroups[i]));
\r
439 private static void writeIpv6AddressRelatedEntry(MatchEntries entry, ByteBuf out, int value) {
\r
440 int fieldValue = value << 1;
\r
441 String[] addressGroups = entry.getAugmentation(Ipv6AddressMatchEntry.class).getIpv6Address().getValue().split(":");
\r
442 String[] address = parseIpv6Address(addressGroups);
\r
443 if (entry.isHasMask()) {
\r
444 fieldValue = fieldValue | 1;
\r
445 out.writeByte(fieldValue);
\r
446 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
447 out.writeByte((8 * Short.SIZE) / Byte.SIZE + mask.length);
\r
448 for (int i = 0; i < address.length; i++) {
\r
449 out.writeShort(Integer.parseInt(addressGroups[i], 16));
\r
451 out.writeBytes(mask);
\r
453 out.writeByte(fieldValue);
\r
454 out.writeByte((8 * Short.SIZE) / Byte.SIZE);
\r
455 for (int i = 0; i < addressGroups.length; i++) {
\r
456 out.writeShort(Integer.parseInt(addressGroups[i], 16));
\r
461 private static String[] parseIpv6Address(String[] addressGroups) {
\r
462 final byte GROUPS_IN_IPV6_ADDRESS = 8;
\r
463 int countEmpty = 0;
\r
464 for (int i = 0; i < addressGroups.length; i++) {
\r
465 if (addressGroups[i].equals("")){
\r
469 String[] ready = new String[GROUPS_IN_IPV6_ADDRESS];
\r
470 switch (countEmpty) {
\r
472 ready = addressGroups;
\r
475 int zerosToBePushed = GROUPS_IN_IPV6_ADDRESS - addressGroups.length + 1;
\r
477 for (int i = 0; i < addressGroups.length; i++) {
\r
478 if (addressGroups[i].equals("")) {
\r
479 for (int j = 0; j < zerosToBePushed; j++) {
\r
484 ready[i + pushed] = addressGroups[i];
\r
489 Arrays.fill(ready, "0");
\r
490 ready[ready.length - 1] = addressGroups[addressGroups.length - 1];
\r
493 Arrays.fill(ready, "0");
\r
503 * Computes length of match (in bytes)
\r
505 * @return length of ofp_match (excluding padding)
\r
507 public static int computeMatchLength(Match match) {
\r
508 final byte MATCH_TYPE_AND_LENGTH_SIZE = 4;
\r
510 if (match != null) {
\r
511 length += MATCH_TYPE_AND_LENGTH_SIZE + computeMatchEntriesLength(match.getMatchEntries());
\r
517 * Computes length of MatchEntries (in bytes)
\r
518 * @param matchEntries list of match entries (oxm_fields)
\r
519 * @return length of MatchEntries
\r
521 public static int computeMatchEntriesLength(List<MatchEntries> matchEntries) {
\r
522 final byte MATCH_ENTRY_HEADER_LENGTH = 4;
\r
524 if (matchEntries != null) {
\r
525 for (MatchEntries entry : matchEntries) {
\r
526 length += MATCH_ENTRY_HEADER_LENGTH;
\r
527 Class<? extends MatchField> field = entry.getOxmMatchField();
\r
528 if (field.equals(InPort.class)) {
\r
529 length += Integer.SIZE / Byte.SIZE;
\r
530 } else if (field.equals(InPhyPort.class)) {
\r
531 length += Integer.SIZE / Byte.SIZE;
\r
532 } else if (field.equals(Metadata.class)) {
\r
533 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
534 } else if (field.equals(EthDst.class)) {
\r
535 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
536 } else if (field.equals(EthSrc.class)) {
\r
537 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
538 } else if (field.equals(EthType.class)) {
\r
539 length += Short.SIZE / Byte.SIZE;
\r
540 } else if (field.equals(VlanVid.class)) {
\r
541 length += computePossibleMaskEntryLength(entry, Short.SIZE / Byte.SIZE);
\r
542 } else if (field.equals(VlanPcp.class)) {
\r
543 length += Byte.SIZE / Byte.SIZE;
\r
544 } else if (field.equals(IpDscp.class)) {
\r
545 length += Byte.SIZE / Byte.SIZE;
\r
546 } else if (field.equals(IpEcn.class)) {
\r
547 length += Byte.SIZE / Byte.SIZE;
\r
548 } else if (field.equals(IpProto.class)) {
\r
549 length += Byte.SIZE / Byte.SIZE;
\r
550 } else if (field.equals(Ipv4Src.class)) {
\r
551 length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);
\r
552 } else if (field.equals(Ipv4Dst.class)) {
\r
553 length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);
\r
554 } else if (field.equals(TcpSrc.class)) {
\r
555 length += Short.SIZE / Byte.SIZE;
\r
556 } else if (field.equals(TcpDst.class)) {
\r
557 length += Short.SIZE / Byte.SIZE;
\r
558 } else if (field.equals(UdpSrc.class)) {
\r
559 length += Short.SIZE / Byte.SIZE;
\r
560 } else if (field.equals(UdpDst.class)) {
\r
561 length += Short.SIZE / Byte.SIZE;
\r
562 } else if (field.equals(SctpSrc.class)) {
\r
563 length += Short.SIZE / Byte.SIZE;
\r
564 } else if (field.equals(SctpDst.class)) {
\r
565 length += Short.SIZE / Byte.SIZE;
\r
566 } else if (field.equals(Icmpv4Type.class)) {
\r
567 length += Byte.SIZE / Byte.SIZE;
\r
568 } else if (field.equals(Icmpv4Code.class)) {
\r
569 length += Byte.SIZE / Byte.SIZE;
\r
570 } else if (field.equals(ArpOp.class)) {
\r
571 length += Short.SIZE / Byte.SIZE;
\r
572 } else if (field.equals(ArpSpa.class)) {
\r
573 length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);
\r
574 } else if (field.equals(ArpTpa.class)) {
\r
575 length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);
\r
576 } else if (field.equals(ArpSha.class)) {
\r
577 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
578 } else if (field.equals(ArpTha.class)) {
\r
579 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
580 } else if (field.equals(Ipv6Src.class)) {
\r
581 length += computePossibleMaskEntryLength(entry, 8 * (Short.SIZE / Byte.SIZE));
\r
582 } else if (field.equals(Ipv6Dst.class)) {
\r
583 length += computePossibleMaskEntryLength(entry, 8 * (Short.SIZE / Byte.SIZE));
\r
584 } else if (field.equals(Ipv6Flabel.class)) {
\r
585 length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);
\r
586 } else if (field.equals(Icmpv6Type.class)) {
\r
587 length += Byte.SIZE / Byte.SIZE;
\r
588 } else if (field.equals(Icmpv6Code.class)) {
\r
589 length += Byte.SIZE / Byte.SIZE;
\r
590 } else if (field.equals(Ipv6NdTarget.class)) {
\r
591 length += computePossibleMaskEntryLength(entry, 8 * (Short.SIZE / Byte.SIZE));
\r
592 } else if (field.equals(Ipv6NdSll.class)) {
\r
593 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
594 } else if (field.equals(Ipv6NdTll.class)) {
\r
595 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
596 } else if (field.equals(MplsLabel.class)) {
\r
597 length += Integer.SIZE / Byte.SIZE;
\r
598 } else if (field.equals(MplsTc.class)) {
\r
599 length += Byte.SIZE / Byte.SIZE;
\r
600 } else if (field.equals(MplsBos.class)) {
\r
601 length += Byte.SIZE / Byte.SIZE;
\r
602 } else if (field.equals(PbbIsid.class)) {
\r
603 length += computePossibleMaskEntryLength(entry, Integer.SIZE / Byte.SIZE);
\r
604 } else if (field.equals(TunnelId.class)) {
\r
605 length += computePossibleMaskEntryLength(entry, Long.SIZE / Byte.SIZE);
\r
606 } else if (field.equals(Ipv6Exthdr.class)) {
\r
607 length += computePossibleMaskEntryLength(entry, Short.SIZE / Byte.SIZE);
\r
614 private static int computePossibleMaskEntryLength(MatchEntries entry, int length) {
\r
615 int entryLength = length;
\r
616 if (entry.isHasMask()) {
\r
619 return entryLength;
\r