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.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.BosMatchEntry;
\r
12 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.DscpMatchEntry;
\r
13 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.EcnMatchEntry;
\r
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.EthTypeMatchEntry;
\r
15 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv4CodeMatchEntry;
\r
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv4TypeMatchEntry;
\r
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv6CodeMatchEntry;
\r
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Icmpv6TypeMatchEntry;
\r
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Ipv4AddressMatchEntry;
\r
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Ipv6AddressMatchEntry;
\r
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.Ipv6FlabelMatchEntry;
\r
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.IsidMatchEntry;
\r
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MacAddressMatchEntry;
\r
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MaskMatchEntry;
\r
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MetadataMatchEntry;
\r
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.MplsLabelMatchEntry;
\r
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.OpCodeMatchEntry;
\r
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PortMatchEntry;
\r
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PortNumberMatchEntry;
\r
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.ProtocolNumberMatchEntry;
\r
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PseudoFieldMatchEntry;
\r
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.PseudoFieldMatchEntry.PseudoField;
\r
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.TcMatchEntry;
\r
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.VlanPcpMatchEntry;
\r
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev131002.VlanVidMatchEntry;
\r
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.StandardMatchType;
\r
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpOp;
\r
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpSha;
\r
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpSpa;
\r
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpTha;
\r
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ArpTpa;
\r
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Clazz;
\r
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.EthDst;
\r
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.EthSrc;
\r
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.EthType;
\r
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.ExperimenterClass;
\r
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv4Code;
\r
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv4Type;
\r
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv6Code;
\r
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Icmpv6Type;
\r
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.InPhyPort;
\r
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.InPort;
\r
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.IpDscp;
\r
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.IpEcn;
\r
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.IpProto;
\r
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv4Dst;
\r
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv4Src;
\r
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Dst;
\r
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Exthdr;
\r
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Flabel;
\r
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6NdSll;
\r
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6NdTarget;
\r
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6NdTll;
\r
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Ipv6Src;
\r
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MatchField;
\r
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Metadata;
\r
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MplsBos;
\r
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MplsLabel;
\r
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.MplsTc;
\r
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Nxm0Class;
\r
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.Nxm1Class;
\r
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.OpenflowBasicClass;
\r
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.OxmMatchType;
\r
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.PbbIsid;
\r
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.SctpDst;
\r
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.SctpSrc;
\r
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.TcpDst;
\r
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.TcpSrc;
\r
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.TunnelId;
\r
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.UdpDst;
\r
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.UdpSrc;
\r
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.VlanPcp;
\r
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.VlanVid;
\r
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev130731.oxm.fields.MatchEntries;
\r
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.match.grouping.Match;
\r
86 import org.slf4j.Logger;
\r
87 import org.slf4j.LoggerFactory;
\r
90 * Serializes ofp_match (OpenFlow v1.3) and its oxm_fields structures
\r
91 * @author michal.polkorab
\r
92 * @author timotej.kubas
\r
94 public class MatchSerializer {
\r
95 private static final Logger LOGGER = LoggerFactory.getLogger(MatchSerializer.class);
\r
96 private static final byte STANDARD_MATCH_TYPE_CODE = 0;
\r
97 private static final byte OXM_MATCH_TYPE_CODE = 1;
\r
98 private static final int NXM0_CLASS_CODE = 0x0000;
\r
99 private static final int NXM1_CLASS_CODE = 0x0001;
\r
100 private static final int OPENFLOW_BASIC_CLASS_CODE = 0x8000;
\r
101 private static final int EXPERIMENTER_CLASS_CODE = 0xFFFF;
\r
102 private static final byte MATCH_TYPE_AND_LENGTH_SIZE = 4;
\r
103 private static final byte MATCH_ENTRY_HEADER_LENGTH = 4;
\r
106 * Encodes match (OpenFlow v1.3)
\r
107 * @param match ofp_match object
\r
108 * @param out output ByteBuf
\r
110 public static void encodeMatch(Match match, ByteBuf out) {
\r
111 if (match == null) {
\r
112 LOGGER.debug("Match is null");
\r
115 encodeType(match, out);
\r
116 // Length of ofp_match (excluding padding)
\r
117 int length = computeMatchLengthInternal(match);
\r
118 out.writeShort(length);
\r
119 encodeMatchEntries(match.getMatchEntries(), out);
\r
120 int paddingRemainder = length % EncodeConstants.PADDING;
\r
121 if (paddingRemainder != 0) {
\r
122 ByteBufUtils.padBuffer(EncodeConstants.PADDING - paddingRemainder, out);
\r
126 private static void encodeType(Match match, ByteBuf out) {
\r
127 if (match.getType().isAssignableFrom(StandardMatchType.class)) {
\r
128 out.writeShort(STANDARD_MATCH_TYPE_CODE);
\r
129 } else if (match.getType().isAssignableFrom(OxmMatchType.class)) {
\r
130 out.writeShort(OXM_MATCH_TYPE_CODE);
\r
135 * Encodes MatchEntries
\r
136 * @param matchEntries list of match entries (oxm_fields)
\r
137 * @param out output ByteBuf
\r
139 public static void encodeMatchEntries(List<MatchEntries> matchEntries, ByteBuf out) {
\r
140 if (matchEntries == null) {
\r
141 LOGGER.warn("Match entries are null");
\r
144 for (MatchEntries entry : matchEntries) {
\r
145 encodeClass(entry.getOxmClass(), out);
\r
146 encodeRest(entry, out);
\r
150 private static void encodeClass(Class<? extends Clazz> clazz, ByteBuf out) {
\r
151 if (clazz.isAssignableFrom(Nxm0Class.class)) {
\r
152 out.writeShort(NXM0_CLASS_CODE);
\r
153 } else if (clazz.isAssignableFrom(Nxm1Class.class)) {
\r
154 out.writeShort(NXM1_CLASS_CODE);
\r
155 } else if (clazz.isAssignableFrom(OpenflowBasicClass.class)) {
\r
156 out.writeShort(OPENFLOW_BASIC_CLASS_CODE);
\r
157 } else if (clazz.isAssignableFrom(ExperimenterClass.class)) {
\r
158 out.writeShort(EXPERIMENTER_CLASS_CODE);
\r
162 private static void encodeRest(MatchEntries entry, ByteBuf out) {
\r
163 int fieldValue = 0;
\r
164 Class<? extends MatchField> field = entry.getOxmMatchField();
\r
165 if (field.isAssignableFrom(InPort.class)) {
\r
167 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_INT_IN_BYTES);
\r
168 out.writeInt(entry.getAugmentation(PortNumberMatchEntry.class).getPortNumber().getValue().intValue());
\r
169 } else if (field.isAssignableFrom(InPhyPort.class)) {
\r
171 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_INT_IN_BYTES);
\r
172 out.writeInt(entry.getAugmentation(PortNumberMatchEntry.class).getPortNumber().getValue().intValue());
\r
173 } else if (field.isAssignableFrom(Metadata.class)) {
\r
175 writeMetadataRelatedEntry(entry, out, fieldValue);
\r
176 } else if (field.isAssignableFrom(EthDst.class)) {
\r
178 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
179 } else if (field.isAssignableFrom(EthSrc.class)) {
\r
181 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
182 } else if (field.isAssignableFrom(EthType.class)) {
\r
184 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
\r
185 out.writeShort(entry.getAugmentation(EthTypeMatchEntry.class).getEthType().getValue().shortValue());
\r
186 } else if (field.isAssignableFrom(VlanVid.class)) {
\r
188 fieldValue = fieldValue << 1;
\r
189 VlanVidMatchEntry vlanVid = entry.getAugmentation(VlanVidMatchEntry.class);
\r
190 int vlanVidValue = vlanVid.getVlanVid();
\r
191 if (vlanVid.isCfiBit()) {
\r
192 short cfi = 1 << 12; // 13-th bit
\r
193 vlanVidValue = vlanVidValue | cfi;
\r
195 if (entry.isHasMask()) {
\r
196 fieldValue = fieldValue | 1;
\r
197 out.writeByte(fieldValue);
\r
198 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
199 out.writeByte(EncodeConstants.SIZE_OF_SHORT_IN_BYTES + mask.length);
\r
200 out.writeShort(vlanVidValue);
\r
201 out.writeBytes(mask);
\r
203 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
\r
204 out.writeShort(vlanVidValue);
\r
206 } else if (field.isAssignableFrom(VlanPcp.class)) {
\r
208 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);
\r
209 out.writeByte(entry.getAugmentation(VlanPcpMatchEntry.class).getVlanPcp().byteValue());
\r
210 } else if (field.isAssignableFrom(IpDscp.class)) {
\r
212 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);
\r
213 out.writeByte(entry.getAugmentation(DscpMatchEntry.class).getDscp().getValue());
\r
214 } else if (field.isAssignableFrom(IpEcn.class)) {
\r
216 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);
\r
217 out.writeByte(entry.getAugmentation(EcnMatchEntry.class).getEcn());
\r
218 } else if (field.isAssignableFrom(IpProto.class)) {
\r
220 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);
\r
221 out.writeByte(entry.getAugmentation(ProtocolNumberMatchEntry.class).getProtocolNumber());
\r
222 } else if (field.isAssignableFrom(Ipv4Src.class)) {
\r
224 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
\r
225 } else if (field.isAssignableFrom(Ipv4Dst.class)) {
\r
227 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
\r
228 } else if (field.isAssignableFrom(TcpSrc.class)) {
\r
230 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
\r
231 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
232 } else if (field.isAssignableFrom(TcpDst.class)) {
\r
234 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
\r
235 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
236 } else if (field.isAssignableFrom(UdpSrc.class)) {
\r
238 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
\r
239 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
240 } else if (field.isAssignableFrom(UdpDst.class)) {
\r
242 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
\r
243 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
244 } else if (field.isAssignableFrom(SctpSrc.class)) {
\r
246 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
\r
247 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
248 } else if (field.isAssignableFrom(SctpDst.class)) {
\r
250 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
\r
251 out.writeShort(entry.getAugmentation(PortMatchEntry.class).getPort().getValue().intValue());
\r
252 } else if (field.isAssignableFrom(Icmpv4Type.class)) {
\r
254 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);
\r
255 out.writeByte(entry.getAugmentation(Icmpv4TypeMatchEntry.class).getIcmpv4Type());
\r
256 } else if (field.isAssignableFrom(Icmpv4Code.class)) {
\r
258 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);
\r
259 out.writeByte(entry.getAugmentation(Icmpv4CodeMatchEntry.class).getIcmpv4Code());
\r
260 } else if (field.isAssignableFrom(ArpOp.class)) {
\r
262 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
\r
263 out.writeShort(entry.getAugmentation(OpCodeMatchEntry.class).getOpCode());
\r
264 } else if (field.isAssignableFrom(ArpSpa.class)) {
\r
266 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
\r
267 } else if (field.isAssignableFrom(ArpTpa.class)) {
\r
269 writeIpv4AddressRelatedEntry(entry, out, fieldValue);
\r
270 } else if (field.isAssignableFrom(ArpSha.class)) {
\r
272 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
273 } else if (field.isAssignableFrom(ArpTha.class)) {
\r
275 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
276 } else if (field.isAssignableFrom(Ipv6Src.class)) {
\r
278 writeIpv6AddressRelatedEntry(entry, out, fieldValue);
\r
279 } else if (field.isAssignableFrom(Ipv6Dst.class)) {
\r
281 writeIpv6AddressRelatedEntry(entry, out, fieldValue);
\r
282 } else if (field.isAssignableFrom(Ipv6Flabel.class)) {
\r
284 fieldValue = fieldValue << 1;
\r
285 if (entry.isHasMask()) {
\r
286 fieldValue = fieldValue | 1;
\r
287 out.writeByte(fieldValue);
\r
288 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
289 out.writeByte(EncodeConstants.SIZE_OF_INT_IN_BYTES + mask.length); // 20 b + mask [OF 1.3.2 spec]
\r
290 LOGGER.warn("Ipv6Flabel match entry: possible wrong length written (wrote 4 - maybe must be 3)");
\r
291 out.writeInt(entry.getAugmentation(Ipv6FlabelMatchEntry.class).getIpv6Flabel().getValue().intValue());
\r
292 out.writeBytes(entry.getAugmentation(MaskMatchEntry.class).getMask());
\r
294 out.writeByte(fieldValue);
\r
295 out.writeByte(EncodeConstants.SIZE_OF_INT_IN_BYTES); // 20 b [OF 1.3.2 spec]
\r
296 LOGGER.warn("Ipv6Flabel match entry: possible wrong length written (wrote 4 - maybe must be 3)");
\r
297 out.writeInt(entry.getAugmentation(Ipv6FlabelMatchEntry.class).getIpv6Flabel().getValue().intValue());
\r
299 } else if (field.isAssignableFrom(Icmpv6Type.class)) {
\r
301 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);
\r
302 out.writeByte(entry.getAugmentation(Icmpv6TypeMatchEntry.class).getIcmpv6Type());
\r
303 } else if (field.isAssignableFrom(Icmpv6Code.class)) {
\r
305 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);
\r
306 out.writeByte(entry.getAugmentation(Icmpv6CodeMatchEntry.class).getIcmpv6Code());
\r
307 } else if (field.isAssignableFrom(Ipv6NdTarget.class)) {
\r
309 writeIpv6AddressRelatedEntry(entry, out, fieldValue);
\r
310 } else if (field.isAssignableFrom(Ipv6NdSll.class)) {
\r
312 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
313 } else if (field.isAssignableFrom(Ipv6NdTll.class)) {
\r
315 writeMacAddressRelatedEntry(entry, out, fieldValue);
\r
316 } else if (field.isAssignableFrom(MplsLabel.class)) {
\r
318 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_INT_IN_BYTES);
\r
319 LOGGER.warn("MplsLabel match entry: possible wrong length written (wrote 4 - maybe must be 3)");
\r
320 out.writeInt(entry.getAugmentation(MplsLabelMatchEntry.class).getMplsLabel().intValue());
\r
321 } else if (field.isAssignableFrom(MplsTc.class)) {
\r
323 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);
\r
324 out.writeByte(entry.getAugmentation(TcMatchEntry.class).getTc());
\r
325 } else if (field.isAssignableFrom(MplsBos.class)) {
\r
327 writeOxmFieldAndLength(out, fieldValue, EncodeConstants.SIZE_OF_BYTE_IN_BYTES);
\r
328 out.writeBoolean(entry.getAugmentation(BosMatchEntry.class).isBos().booleanValue());
\r
329 } else if (field.isAssignableFrom(PbbIsid.class)) {
\r
331 fieldValue = fieldValue << 1;
\r
332 if (entry.isHasMask()) {
\r
333 fieldValue = fieldValue | 1;
\r
334 out.writeByte(fieldValue);
\r
335 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
336 out.writeByte(EncodeConstants.SIZE_OF_LONG_IN_BYTES + mask.length);
\r
337 LOGGER.warn("PbbIsid match entry: possible wrong length written (wrote 4 - maybe must be 3)");
\r
338 out.writeInt(entry.getAugmentation(IsidMatchEntry.class).getIsid().intValue());
\r
339 out.writeBytes(mask);
\r
341 out.writeByte(fieldValue);
\r
342 out.writeByte(EncodeConstants.SIZE_OF_LONG_IN_BYTES);
\r
343 LOGGER.warn("PbbIsid match entry: possible wrong length written (wrote 4 - maybe must be 3)");
\r
344 out.writeInt(entry.getAugmentation(IsidMatchEntry.class).getIsid().intValue());
\r
346 } else if (field.isAssignableFrom(TunnelId.class)) {
\r
348 writeMetadataRelatedEntry(entry, out, fieldValue);
\r
349 } else if (field.isAssignableFrom(Ipv6Exthdr.class)) {
\r
351 fieldValue = fieldValue << 1;
\r
352 PseudoField pseudoField = entry.getAugmentation(PseudoFieldMatchEntry.class).getPseudoField();
\r
353 Map<Integer, Boolean> map = new HashMap<>();
\r
354 map.put(0, pseudoField.isNonext());
\r
355 map.put(1, pseudoField.isEsp());
\r
356 map.put(2, pseudoField.isAuth());
\r
357 map.put(3, pseudoField.isDest());
\r
358 map.put(4, pseudoField.isFrag());
\r
359 map.put(5, pseudoField.isRouter());
\r
360 map.put(6, pseudoField.isHop());
\r
361 map.put(7, pseudoField.isUnrep());
\r
362 map.put(8, pseudoField.isUnseq());
\r
363 int bitmap = ByteBufUtils.fillBitMaskFromMap(map);
\r
364 if (entry.isHasMask()) {
\r
365 fieldValue = fieldValue | 1;
\r
366 out.writeByte(fieldValue);
\r
367 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
368 out.writeByte(EncodeConstants.SIZE_OF_SHORT_IN_BYTES + mask.length);
\r
369 out.writeShort(bitmap);
\r
370 out.writeBytes(mask);
\r
372 out.writeByte(fieldValue);
\r
373 out.writeByte(EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
\r
374 out.writeShort(bitmap);
\r
379 private static void writeOxmFieldAndLength(ByteBuf out, int fieldValue, int length) {
\r
380 int fieldAndMask = fieldValue << 1;
\r
381 out.writeByte(fieldAndMask);
\r
382 out.writeByte(length);
\r
385 private static void writeMetadataRelatedEntry(MatchEntries entry, ByteBuf out, int value) {
\r
386 int fieldValue = value << 1;
\r
387 if (entry.isHasMask()) {
\r
388 fieldValue = fieldValue | 1;
\r
389 out.writeByte(fieldValue);
\r
390 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
391 out.writeByte(EncodeConstants.SIZE_OF_LONG_IN_BYTES + mask.length);
\r
392 out.writeBytes(entry.getAugmentation(MetadataMatchEntry.class).getMetadata());
\r
393 out.writeBytes(mask);
\r
395 out.writeByte(fieldValue);
\r
396 out.writeByte(EncodeConstants.SIZE_OF_LONG_IN_BYTES);
\r
397 out.writeBytes(entry.getAugmentation(MetadataMatchEntry.class).getMetadata());
\r
401 private static void writeMacAddressRelatedEntry(MatchEntries entry, ByteBuf out, int value) {
\r
402 int fieldValue = value << 1;
\r
403 if (entry.isHasMask()) {
\r
404 fieldValue = fieldValue | 1;
\r
405 out.writeByte(fieldValue);
\r
406 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
407 out.writeByte(EncodeConstants.MAC_ADDRESS_LENGTH + mask.length); // 48 b + mask [OF 1.3.2 spec]
\r
408 String macAddress = entry.getAugmentation(MacAddressMatchEntry.class).getMacAddress().getValue();
\r
409 out.writeBytes(ByteBufUtils.macAddressToBytes(macAddress));
\r
410 out.writeBytes(mask);
\r
412 out.writeByte(fieldValue);
\r
413 out.writeByte(EncodeConstants.MAC_ADDRESS_LENGTH); // 48 b [OF 1.3.2 spec]
\r
414 String macAddress = entry.getAugmentation(MacAddressMatchEntry.class).getMacAddress().getValue();
\r
415 out.writeBytes(ByteBufUtils.macAddressToBytes(macAddress));
\r
419 private static void writeIpv4AddressRelatedEntry(MatchEntries entry, ByteBuf out, int value) {
\r
420 int fieldValue = value << 1;
\r
421 if (entry.isHasMask()) {
\r
422 fieldValue = fieldValue | 1;
\r
423 out.writeByte(fieldValue);
\r
424 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
425 out.writeByte(EncodeConstants.SIZE_OF_INT_IN_BYTES + mask.length);
\r
426 writeIpv4Address(entry, out);
\r
427 out.writeBytes(mask);
\r
429 out.writeByte(fieldValue);
\r
430 out.writeByte(EncodeConstants.SIZE_OF_INT_IN_BYTES);
\r
431 writeIpv4Address(entry, out);
\r
435 private static void writeIpv4Address(MatchEntries entry, ByteBuf out) {
\r
436 String[] addressGroups = entry.getAugmentation(Ipv4AddressMatchEntry.class).getIpv4Address().getValue().split("\\.");
\r
437 for (int i = 0; i < addressGroups.length; i++) {
\r
438 out.writeByte(Integer.parseInt(addressGroups[i]));
\r
442 private static void writeIpv6AddressRelatedEntry(MatchEntries entry, ByteBuf out, int value) {
\r
443 int fieldValue = value << 1;
\r
444 String[] addressGroups = entry.getAugmentation(Ipv6AddressMatchEntry.class).getIpv6Address().getValue().split(":");
\r
445 String[] address = parseIpv6Address(addressGroups);
\r
446 if (entry.isHasMask()) {
\r
447 fieldValue = fieldValue | 1;
\r
448 out.writeByte(fieldValue);
\r
449 byte[] mask = entry.getAugmentation(MaskMatchEntry.class).getMask();
\r
450 out.writeByte(EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES + mask.length);
\r
451 for (int i = 0; i < address.length; i++) {
\r
452 out.writeShort(Integer.parseInt(addressGroups[i], 16));
\r
454 out.writeBytes(mask);
\r
456 out.writeByte(fieldValue);
\r
457 out.writeByte(EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES);
\r
458 for (int i = 0; i < addressGroups.length; i++) {
\r
459 out.writeShort(Integer.parseInt(addressGroups[i], 16));
\r
464 private static String[] parseIpv6Address(String[] addressGroups) {
\r
465 int countEmpty = 0;
\r
466 for (int i = 0; i < addressGroups.length; i++) {
\r
467 if (addressGroups[i].equals("")){
\r
471 String[] ready = new String[EncodeConstants.GROUPS_IN_IPV6_ADDRESS];
\r
472 switch (countEmpty) {
\r
474 ready = addressGroups;
\r
477 int zerosToBePushed = EncodeConstants.GROUPS_IN_IPV6_ADDRESS - addressGroups.length + 1;
\r
479 for (int i = 0; i < addressGroups.length; i++) {
\r
480 if (addressGroups[i].equals("")) {
\r
481 for (int j = 0; j < zerosToBePushed; j++) {
\r
486 ready[i + pushed] = addressGroups[i];
\r
491 Arrays.fill(ready, "0");
\r
492 ready[ready.length - 1] = addressGroups[addressGroups.length - 1];
\r
495 Arrays.fill(ready, "0");
\r
505 * Computes length of match (in bytes)
\r
507 * @return length of ofp_match (excluding padding)
\r
509 public static int computeMatchLengthInternal(Match match) {
\r
511 if (match != null) {
\r
512 length += MATCH_TYPE_AND_LENGTH_SIZE + computeMatchEntriesLength(match.getMatchEntries());
\r
518 * Computes length of match (in bytes)
\r
520 * @return length of ofp_match (excluding padding)
\r
522 public static int computeMatchLength(Match match) {
\r
523 int length = computeMatchLengthInternal(match);
\r
524 int paddingRemainder = length % EncodeConstants.PADDING;
\r
525 if (paddingRemainder != 0) {
\r
526 length += EncodeConstants.PADDING - paddingRemainder;
\r
532 * Computes length of MatchEntries (in bytes)
\r
533 * @param matchEntries list of match entries (oxm_fields)
\r
534 * @return length of MatchEntries
\r
536 public static int computeMatchEntriesLength(List<MatchEntries> matchEntries) {
\r
538 if (matchEntries != null) {
\r
539 for (MatchEntries entry : matchEntries) {
\r
540 length += MATCH_ENTRY_HEADER_LENGTH;
\r
541 Class<? extends MatchField> field = entry.getOxmMatchField();
\r
542 if (field.isAssignableFrom(InPort.class)) {
\r
543 length += EncodeConstants.SIZE_OF_INT_IN_BYTES;
\r
544 } else if (field.isAssignableFrom(InPhyPort.class)) {
\r
545 length += EncodeConstants.SIZE_OF_INT_IN_BYTES;
\r
546 } else if (field.isAssignableFrom(Metadata.class)) {
\r
547 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_LONG_IN_BYTES);
\r
548 } else if (field.isAssignableFrom(EthDst.class)) {
\r
549 length += computePossibleMaskEntryLength(entry, EncodeConstants.MAC_ADDRESS_LENGTH);
\r
550 } else if (field.isAssignableFrom(EthSrc.class)) {
\r
551 length += computePossibleMaskEntryLength(entry, EncodeConstants.MAC_ADDRESS_LENGTH);
\r
552 } else if (field.isAssignableFrom(EthType.class)) {
\r
553 length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
\r
554 } else if (field.isAssignableFrom(VlanVid.class)) {
\r
555 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
\r
556 } else if (field.isAssignableFrom(VlanPcp.class)) {
\r
557 length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;
\r
558 } else if (field.isAssignableFrom(IpDscp.class)) {
\r
559 length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;
\r
560 } else if (field.isAssignableFrom(IpEcn.class)) {
\r
561 length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;
\r
562 } else if (field.isAssignableFrom(IpProto.class)) {
\r
563 length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;
\r
564 } else if (field.isAssignableFrom(Ipv4Src.class)) {
\r
565 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);
\r
566 } else if (field.isAssignableFrom(Ipv4Dst.class)) {
\r
567 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);
\r
568 } else if (field.isAssignableFrom(TcpSrc.class)) {
\r
569 length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
\r
570 } else if (field.isAssignableFrom(TcpDst.class)) {
\r
571 length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
\r
572 } else if (field.isAssignableFrom(UdpSrc.class)) {
\r
573 length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
\r
574 } else if (field.isAssignableFrom(UdpDst.class)) {
\r
575 length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
\r
576 } else if (field.isAssignableFrom(SctpSrc.class)) {
\r
577 length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
\r
578 } else if (field.isAssignableFrom(SctpDst.class)) {
\r
579 length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
\r
580 } else if (field.isAssignableFrom(Icmpv4Type.class)) {
\r
581 length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;
\r
582 } else if (field.isAssignableFrom(Icmpv4Code.class)) {
\r
583 length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;
\r
584 } else if (field.isAssignableFrom(ArpOp.class)) {
\r
585 length += EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
\r
586 } else if (field.isAssignableFrom(ArpSpa.class)) {
\r
587 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);
\r
588 } else if (field.isAssignableFrom(ArpTpa.class)) {
\r
589 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);
\r
590 } else if (field.isAssignableFrom(ArpSha.class)) {
\r
591 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_LONG_IN_BYTES);
\r
592 } else if (field.isAssignableFrom(ArpTha.class)) {
\r
593 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_LONG_IN_BYTES);
\r
594 } else if (field.isAssignableFrom(Ipv6Src.class)) {
\r
595 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES);
\r
596 } else if (field.isAssignableFrom(Ipv6Dst.class)) {
\r
597 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES);
\r
598 } else if (field.isAssignableFrom(Ipv6Flabel.class)) {
\r
599 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);
\r
600 } else if (field.isAssignableFrom(Icmpv6Type.class)) {
\r
601 length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;
\r
602 } else if (field.isAssignableFrom(Icmpv6Code.class)) {
\r
603 length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;
\r
604 } else if (field.isAssignableFrom(Ipv6NdTarget.class)) {
\r
605 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES);
\r
606 } else if (field.isAssignableFrom(Ipv6NdSll.class)) {
\r
607 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_LONG_IN_BYTES);
\r
608 } else if (field.isAssignableFrom(Ipv6NdTll.class)) {
\r
609 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_LONG_IN_BYTES);
\r
610 } else if (field.isAssignableFrom(MplsLabel.class)) {
\r
611 length += EncodeConstants.SIZE_OF_INT_IN_BYTES;
\r
612 } else if (field.isAssignableFrom(MplsTc.class)) {
\r
613 length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;
\r
614 } else if (field.isAssignableFrom(MplsBos.class)) {
\r
615 length += EncodeConstants.SIZE_OF_BYTE_IN_BYTES;
\r
616 } else if (field.isAssignableFrom(PbbIsid.class)) {
\r
617 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_INT_IN_BYTES);
\r
618 } else if (field.isAssignableFrom(TunnelId.class)) {
\r
619 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_LONG_IN_BYTES);
\r
620 } else if (field.isAssignableFrom(Ipv6Exthdr.class)) {
\r
621 length += computePossibleMaskEntryLength(entry, EncodeConstants.SIZE_OF_SHORT_IN_BYTES);
\r
628 private static int computePossibleMaskEntryLength(MatchEntries entry, int length) {
\r
629 int entryLength = length;
\r
630 if (entry.isHasMask()) {
\r
633 return entryLength;
\r