Support for packet type match field
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / core / sal / convertor / match / MatchConvertor.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match;
10
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Collection;
14 import java.util.List;
15 import java.util.Optional;
16 import org.opendaylight.openflowjava.util.ByteBufUtils;
17 import org.opendaylight.openflowplugin.api.OFConstants;
18 import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
19 import org.opendaylight.openflowplugin.extension.api.ConverterExtensionKey;
20 import org.opendaylight.openflowplugin.extension.api.ConvertorToOFJava;
21 import org.opendaylight.openflowplugin.extension.api.core.extension.ExtensionConverterProvider;
22 import org.opendaylight.openflowplugin.openflow.md.core.extension.ExtensionResolvers;
23 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor;
24 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.OFApprovedExperimenterIds;
25 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.Convertor;
26 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.ConvertorProcessor;
27 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.data.VersionConvertorData;
28 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.flow.FlowConvertor;
29 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.cases.SalToOfArpMatchCase;
30 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.cases.SalToOfIpv4MatchArbitraryBitMaskCase;
31 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.cases.SalToOfIpv4MatchCase;
32 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.cases.SalToOfIpv6MatchArbitraryBitMaskCase;
33 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.cases.SalToOfIpv6MatchCase;
34 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.cases.SalToOfSctpMatchCase;
35 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.cases.SalToOfTcpMatchCase;
36 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.cases.SalToOfTunnelIpv4MatchCase;
37 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.cases.SalToOfUdpMatchCase;
38 import org.opendaylight.openflowplugin.openflow.md.core.session.OFSessionUtil;
39 import org.opendaylight.openflowplugin.openflow.md.util.ByteUtil;
40 import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.field._case.SetField;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestination;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetSource;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetType;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatch;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv4Match;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv6Match;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatch;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer4Match;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.PacketTypeMatch;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.ProtocolMatchFields;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.TcpFlagsMatch;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatch;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.protocol.match.fields.Pbb;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.vlan.match.fields.VlanId;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.approved.extensions.rev160802.TcpFlags;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.approved.extensions.rev160802.TcpFlagsContainer;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.approved.extensions.rev160802.TcpFlagsContainerBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.approved.extensions.rev160802.oxm.container.match.entry.value.experimenter.id._case.TcpFlagsBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev150225.oxm.container.match.entry.value.ExperimenterIdCaseBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev150225.oxm.container.match.entry.value.experimenter.id._case.ExperimenterBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.EtherType;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ExperimenterId;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortNumber;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.EthDst;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.EthSrc;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.EthType;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.ExperimenterClass;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.Icmpv4Code;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.Icmpv4Type;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.Icmpv6Code;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.Icmpv6Type;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.InPhyPort;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.InPort;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.IpEcn;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.IpProto;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.Metadata;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.MplsBos;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.MplsLabel;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.MplsTc;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.OpenflowBasicClass;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.PacketType;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.PbbIsid;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.TunnelId;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.VlanVid;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntry;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntryBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.EthDstCaseBuilder;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.EthSrcCaseBuilder;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.EthTypeCaseBuilder;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.Icmpv4CodeCaseBuilder;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.Icmpv4TypeCaseBuilder;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.Icmpv6CodeCaseBuilder;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.Icmpv6TypeCaseBuilder;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.InPhyPortCaseBuilder;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.InPortCaseBuilder;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.IpEcnCaseBuilder;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.IpProtoCaseBuilder;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.MetadataCaseBuilder;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.MplsBosCaseBuilder;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.MplsLabelCaseBuilder;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.MplsTcCaseBuilder;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.PacketTypeCaseBuilder;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.PbbIsidCaseBuilder;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.TunnelIdCaseBuilder;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.VlanVidCaseBuilder;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.eth.dst._case.EthDstBuilder;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.eth.src._case.EthSrcBuilder;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.eth.type._case.EthTypeBuilder;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.icmpv4.code._case.Icmpv4CodeBuilder;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.icmpv4.type._case.Icmpv4TypeBuilder;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.icmpv6.code._case.Icmpv6CodeBuilder;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.icmpv6.type._case.Icmpv6TypeBuilder;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.in.phy.port._case.InPhyPortBuilder;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.in.port._case.InPortBuilder;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.ip.ecn._case.IpEcnBuilder;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.ip.proto._case.IpProtoBuilder;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.mpls.bos._case.MplsBosBuilder;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.mpls.label._case.MplsLabelBuilder;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.mpls.tc._case.MplsTcBuilder;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.packet.type._case.PacketTypeBuilder;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.pbb.isid._case.PbbIsidBuilder;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.tunnel.id._case.TunnelIdBuilder;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.vlan.vid._case.VlanVidBuilder;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.ExtensionKey;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.GeneralExtensionListGrouping;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.list.grouping.ExtensionList;
131
132 /**
133  * Utility class for converting a MD-SAL Flow into the OF flow mod.
134  */
135 public class MatchConvertor extends Convertor<Match, List<MatchEntry>, VersionConvertorData> {
136     private static final List<Class<?>> TYPES = Arrays.asList(
137             Match.class,
138             org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match.class,
139             org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.mod.removed.Match.class,
140             org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.packet.received.Match.class,
141             org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.packet.in.message.Match.class,
142             org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.feature.prop.type.table.feature
143                 .prop.type.Match.class,
144             SetField.class);
145
146     private static final ConvertorProcessor<Layer3Match, List<MatchEntry>, VersionConvertorData> LAYER3_PROCESSOR =
147         new ConvertorProcessor<Layer3Match, List<MatchEntry>, VersionConvertorData>()
148             .addCase(new SalToOfIpv4MatchArbitraryBitMaskCase())
149             .addCase(new SalToOfIpv4MatchCase())
150             .addCase(new SalToOfTunnelIpv4MatchCase())
151             .addCase(new SalToOfArpMatchCase())
152             .addCase(new SalToOfIpv6MatchArbitraryBitMaskCase())
153             .addCase(new SalToOfIpv6MatchCase());
154
155     private static final ConvertorProcessor<Layer4Match, List<MatchEntry>, VersionConvertorData> LAYER4_PROCESSOR =
156         new ConvertorProcessor<Layer4Match, List<MatchEntry>, VersionConvertorData>()
157             .addCase(new SalToOfTcpMatchCase())
158             .addCase(new SalToOfUdpMatchCase())
159             .addCase(new SalToOfSctpMatchCase());
160
161     private static final byte[] VLAN_VID_MASK = new byte[]{16, 0};
162
163     private static void layer3Match(final List<MatchEntry> matchEntryList, final Layer3Match layer3Match,
164                                     ConvertorExecutor converterExecutor,
165                                     final ExtensionConverterProvider extensionConvertorProvider) {
166         java.util.Optional<List<MatchEntry>> result = LAYER3_PROCESSOR.process(layer3Match, converterExecutor
167         );
168
169         if (result.isPresent()) {
170             matchEntryList.addAll(result.get());
171         }
172     }
173
174     private static void layer4Match(final List<MatchEntry> matchEntryList, final Layer4Match layer4Match,
175             ConvertorExecutor converterExecutor, final ExtensionConverterProvider extensionConvertorProvider) {
176         java.util.Optional<List<MatchEntry>> result = LAYER4_PROCESSOR.process(layer4Match, converterExecutor
177         );
178
179         if (result.isPresent()) {
180             matchEntryList.addAll(result.get());
181         }
182     }
183
184     private static void inPortMatch(final List<MatchEntry> matchEntryList, NodeConnectorId inPort) {
185         if (inPort == null) {
186             return;
187         }
188
189         //TODO: currently this matchconverter is mapped to OF1.3 in MatchInjector. Will need to revisit during 1.4+
190         final long portNumber = InventoryDataServiceUtil.portNumberfromNodeConnectorId(OpenflowVersion.OF13, inPort);
191         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
192         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
193         matchEntryBuilder.setHasMask(false);
194         matchEntryBuilder.setOxmMatchField(InPort.class);
195         InPortCaseBuilder caseBuilder = new InPortCaseBuilder();
196         InPortBuilder portBuilder = new InPortBuilder();
197         portBuilder.setPortNumber(new PortNumber(portNumber));
198         caseBuilder.setInPort(portBuilder.build());
199         matchEntryBuilder.setMatchEntryValue(caseBuilder.build());
200         matchEntryList.add(matchEntryBuilder.build());
201     }
202
203     private static void inPhyPortMatch(final List<MatchEntry> matchEntryList, NodeConnectorId inPhyPort) {
204         if (inPhyPort == null) {
205             return;
206         }
207
208         //TODO: currently this matchconverter is mapped to OF1.3 in MatchInjector. Will need to revisit during 1.4+
209         final long portNumber = InventoryDataServiceUtil.portNumberfromNodeConnectorId(OpenflowVersion.OF13, inPhyPort);
210         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
211         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
212         matchEntryBuilder.setHasMask(false);
213         matchEntryBuilder.setOxmMatchField(InPhyPort.class);
214         InPhyPortCaseBuilder caseBuilder = new InPhyPortCaseBuilder();
215         InPhyPortBuilder portBuilder = new InPhyPortBuilder();
216         portBuilder.setPortNumber(new PortNumber(portNumber));
217         caseBuilder.setInPhyPort(portBuilder.build());
218         matchEntryBuilder.setMatchEntryValue(caseBuilder.build());
219         matchEntryList.add(matchEntryBuilder.build());
220     }
221
222     private static void metadataMatch(final List<MatchEntry> matchEntryList,
223             final org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Metadata metadata) {
224         if (metadata == null) {
225             return;
226         }
227
228         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
229         final boolean hasmask = metadata.getMetadataMask() != null;
230         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
231         matchEntryBuilder.setOxmMatchField(Metadata.class);
232         MetadataCaseBuilder metadataCaseBuilder = new MetadataCaseBuilder();
233         org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entry.value.grouping.match.entry
234             .value.metadata._case.MetadataBuilder metadataBuilder = new org.opendaylight.yang.gen.v1.urn.opendaylight
235                 .openflow.oxm.rev150225.match.entry.value.grouping.match.entry.value.metadata._case.MetadataBuilder();
236         metadataBuilder.setMetadata(ByteUtil.convertBigIntegerToNBytes(metadata.getMetadata(),
237                 OFConstants.SIZE_OF_LONG_IN_BYTES));
238
239         if (hasmask) {
240             metadataBuilder.setMask(ByteUtil.convertBigIntegerToNBytes(metadata.getMetadataMask(),
241                     OFConstants.SIZE_OF_LONG_IN_BYTES));
242         }
243
244         metadataCaseBuilder.setMetadata(metadataBuilder.build());
245         matchEntryBuilder.setMatchEntryValue(metadataCaseBuilder.build());
246         matchEntryBuilder.setHasMask(hasmask);
247         matchEntryList.add(matchEntryBuilder.build());
248     }
249
250     private static void packetTypeMatch(final List<MatchEntry> matchEntryList, final PacketTypeMatch packetTypeMatch) {
251         if (packetTypeMatch == null) {
252             return;
253         }
254
255         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
256         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
257         matchEntryBuilder.setOxmMatchField(PacketType.class);
258         matchEntryBuilder.setHasMask(false);
259         PacketTypeCaseBuilder packetTypeCaseBuilder = new PacketTypeCaseBuilder();
260         PacketTypeBuilder packetTypeBuilder = new PacketTypeBuilder();
261         packetTypeBuilder.setPacketType(packetTypeMatch.getPacketType());
262         packetTypeCaseBuilder.setPacketType(packetTypeBuilder.build());
263         matchEntryBuilder.setMatchEntryValue(packetTypeCaseBuilder.build());
264         matchEntryList.add(matchEntryBuilder.build());
265     }
266
267     private static void tunnelMatch(final List<MatchEntry> matchEntryList,
268             final org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Tunnel tunnel) {
269         if (tunnel == null) {
270             return;
271         }
272
273         TunnelIdCaseBuilder tunnelIdCaseBuilder = new TunnelIdCaseBuilder();
274         TunnelIdBuilder tunnelIdBuilder = new TunnelIdBuilder();
275         boolean hasMask = tunnel.getTunnelMask() != null;
276
277         if (hasMask) {
278             tunnelIdBuilder.setMask(ByteUtil.convertBigIntegerToNBytes(tunnel.getTunnelMask(),
279                     OFConstants.SIZE_OF_LONG_IN_BYTES));
280         }
281
282         tunnelIdBuilder.setTunnelId(ByteUtil.convertBigIntegerToNBytes(tunnel.getTunnelId(),
283                 OFConstants.SIZE_OF_LONG_IN_BYTES));
284         tunnelIdCaseBuilder.setTunnelId(tunnelIdBuilder.build());
285
286         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
287         matchEntryBuilder.setMatchEntryValue(tunnelIdCaseBuilder.build());
288         matchEntryBuilder.setHasMask(hasMask);
289         matchEntryBuilder.setOxmMatchField(TunnelId.class);
290         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
291         matchEntryList.add(matchEntryBuilder.build());
292     }
293
294     private static void protocolMatchFields(final List<MatchEntry> matchEntryList,
295                                             final ProtocolMatchFields protocolMatchFields) {
296         if (protocolMatchFields == null) {
297             return;
298         }
299
300         if (protocolMatchFields.getMplsLabel() != null) {
301             matchEntryList.add(toOfMplsLabel(protocolMatchFields.getMplsLabel()));
302         }
303
304         if (protocolMatchFields.getMplsBos() != null) {
305             matchEntryList.add(toOfMplsBos(protocolMatchFields.getMplsBos()));
306         }
307
308         if (protocolMatchFields.getMplsTc() != null) {
309             matchEntryList.add(toOfMplsTc(protocolMatchFields.getMplsTc()));
310         }
311
312         if (protocolMatchFields.getPbb() != null) {
313             matchEntryList.add(toOfMplsPbb(protocolMatchFields.getPbb()));
314         }
315     }
316
317     private static void icmpv6Match(final List<MatchEntry> matchEntryList, final Icmpv6Match icmpv6Match) {
318         if (icmpv6Match == null) {
319             return;
320         }
321
322         if (icmpv6Match.getIcmpv6Type() != null) {
323             matchEntryList.add(toOfIcmpv6Type(icmpv6Match.getIcmpv6Type()));
324         }
325
326         if (icmpv6Match.getIcmpv6Code() != null) {
327             matchEntryList.add(toOfIcmpv6Code(icmpv6Match.getIcmpv6Code()));
328         }
329     }
330
331     private static void icmpv4Match(final List<MatchEntry> matchEntryList, final Icmpv4Match icmpv4Match) {
332         if (icmpv4Match == null) {
333             return;
334         }
335
336         if (icmpv4Match.getIcmpv4Type() != null) {
337             matchEntryList.add(toOfIcmpv4Type(icmpv4Match.getIcmpv4Type()));
338         }
339
340         if (icmpv4Match.getIcmpv4Code() != null) {
341             matchEntryList.add(toOfIcmpv4Code(icmpv4Match.getIcmpv4Code()));
342         }
343     }
344
345     private static void ipMatch(final List<MatchEntry> matchEntryList, final IpMatch ipMatch) {
346         if (ipMatch == null) {
347             return;
348         }
349
350         if (ipMatch.getIpDscp() != null) {
351             matchEntryList.add(MatchConvertorUtil.toOfIpDscp(ipMatch.getIpDscp()));
352         }
353
354         if (ipMatch.getIpEcn() != null) {
355             matchEntryList.add(toOfIpEcn(ipMatch.getIpEcn()));
356         }
357
358         if (ipMatch.getIpProtocol() != null) {
359             matchEntryList.add(toOfIpProto(ipMatch.getIpProtocol()));
360         }
361     }
362
363     private static void vlanMatch(final List<MatchEntry> matchEntryList, final VlanMatch vlanMatch) {
364         if (vlanMatch == null) {
365             return;
366         }
367
368         if (vlanMatch.getVlanId() != null) {
369             VlanId vlanId = vlanMatch.getVlanId();
370             MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
371             matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
372             matchEntryBuilder.setOxmMatchField(VlanVid.class);
373             VlanVidBuilder vlanVidBuilder = new VlanVidBuilder();
374             boolean setCfiBit = false;
375             Integer vidEntryValue = 0;
376             boolean hasmask = false;
377
378             if (Boolean.TRUE.equals(vlanId.isVlanIdPresent())) {
379                 setCfiBit = true;
380                 if (vlanId.getVlanId() != null) {
381                     vidEntryValue = vlanId.getVlanId().getValue();
382                 }
383
384                 hasmask = vidEntryValue == 0;
385                 if (hasmask) {
386                     vlanVidBuilder.setMask(VLAN_VID_MASK);
387                 }
388             }
389
390             vlanVidBuilder.setCfiBit(setCfiBit);
391             vlanVidBuilder.setVlanVid(vidEntryValue);
392             VlanVidCaseBuilder vlanVidCaseBuilder = new VlanVidCaseBuilder();
393             vlanVidCaseBuilder.setVlanVid(vlanVidBuilder.build());
394             matchEntryBuilder.setMatchEntryValue(vlanVidCaseBuilder.build());
395             matchEntryBuilder.setHasMask(hasmask);
396             matchEntryList.add(matchEntryBuilder.build());
397         }
398
399         if (vlanMatch.getVlanPcp() != null) {
400             matchEntryList.add(MatchConvertorUtil.toOfVlanPcp(vlanMatch.getVlanPcp()));
401         }
402     }
403
404     private static void ethernetMatch(final List<MatchEntry> matchEntryList, final EthernetMatch ethernetMatch) {
405         if (ethernetMatch == null) {
406             return;
407         }
408
409         EthernetDestination ethernetDestination = ethernetMatch.getEthernetDestination();
410         if (ethernetDestination != null) {
411             MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
412             matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
413             matchEntryBuilder.setOxmMatchField(EthDst.class);
414             EthDstCaseBuilder ethDstCaseBuilder = new EthDstCaseBuilder();
415             EthDstBuilder ethDstBuilder = new EthDstBuilder();
416             ethDstBuilder.setMacAddress(ethernetDestination.getAddress());
417             boolean hasMask = ethernetDestination.getMask() != null;
418
419             if (hasMask) {
420                 ethDstBuilder.setMask(ByteBufUtils.macAddressToBytes(ethernetDestination.getMask().getValue()));
421             }
422
423             ethDstCaseBuilder.setEthDst(ethDstBuilder.build());
424             matchEntryBuilder.setMatchEntryValue(ethDstCaseBuilder.build());
425             matchEntryBuilder.setHasMask(hasMask);
426             matchEntryList.add(matchEntryBuilder.build());
427         }
428
429         EthernetSource ethernetSource = ethernetMatch.getEthernetSource();
430         if (ethernetSource != null) {
431             MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
432             matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
433             matchEntryBuilder.setOxmMatchField(EthSrc.class);
434             EthSrcCaseBuilder ethSrcCaseBuilder = new EthSrcCaseBuilder();
435             EthSrcBuilder ethDstBuilder = new EthSrcBuilder();
436             ethDstBuilder.setMacAddress(ethernetSource.getAddress());
437             boolean hasMask = ethernetSource.getMask() != null;
438
439             if (hasMask) {
440                 ethDstBuilder.setMask(ByteBufUtils.macAddressToBytes(ethernetSource.getMask().getValue()));
441             }
442
443             ethSrcCaseBuilder.setEthSrc(ethDstBuilder.build());
444             matchEntryBuilder.setMatchEntryValue(ethSrcCaseBuilder.build());
445             matchEntryBuilder.setHasMask(hasMask);
446             matchEntryList.add(matchEntryBuilder.build());
447         }
448
449         if (ethernetMatch.getEthernetType() != null) {
450             matchEntryList.add(toOfEthernetType(ethernetMatch.getEthernetType()));
451         }
452     }
453
454     private static void tcpFlagsMatch(List<MatchEntry> matchEntryList, TcpFlagsMatch tcpFlagsMatch) {
455         ExperimenterIdCaseBuilder expIdCaseBuilder = new ExperimenterIdCaseBuilder();
456         if (tcpFlagsMatch != null) {
457             MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
458             matchEntryBuilder.setOxmClass(ExperimenterClass.class);
459             matchEntryBuilder.setHasMask(false);
460             matchEntryBuilder.setOxmMatchField(TcpFlags.class);
461
462             TcpFlagsContainerBuilder tcpFlagsContainerBuilder = new TcpFlagsContainerBuilder();
463             TcpFlagsBuilder tcpFlagsBuilder = new TcpFlagsBuilder();
464             tcpFlagsBuilder.setFlags(tcpFlagsMatch.getTcpFlags());
465             if (tcpFlagsMatch.getTcpFlagsMask() != null) {
466                 matchEntryBuilder.setHasMask(true);
467                 tcpFlagsBuilder.setMask(ByteUtil.unsignedShortToBytes(tcpFlagsMatch.getTcpFlagsMask()));
468             }
469             tcpFlagsContainerBuilder.setTcpFlags(tcpFlagsBuilder.build());
470
471             //Set experimenter ID.
472             ExperimenterBuilder experimenterBuilder = new ExperimenterBuilder();
473             experimenterBuilder.setExperimenter(new ExperimenterId(OFApprovedExperimenterIds.MATCH_TCP_FLAGS_EXP_ID));
474             expIdCaseBuilder.setExperimenter(experimenterBuilder.build());
475
476             expIdCaseBuilder.addAugmentation(TcpFlagsContainer.class, tcpFlagsContainerBuilder.build());
477             matchEntryBuilder.setMatchEntryValue(expIdCaseBuilder.build());
478             matchEntryList.add(matchEntryBuilder.build());
479         }
480     }
481
482     private static MatchEntry toOfMplsPbb(final Pbb pbb) {
483         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
484         final boolean hasmask = pbb.getPbbMask() != null;
485         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
486         matchEntryBuilder.setOxmMatchField(PbbIsid.class);
487         PbbIsidCaseBuilder pbbIsidCaseBuilder = new PbbIsidCaseBuilder();
488         PbbIsidBuilder pbbIsidBuilder = new PbbIsidBuilder();
489         pbbIsidBuilder.setIsid(pbb.getPbbIsid());
490
491         if (hasmask) {
492             pbbIsidBuilder.setMask(ByteUtil.unsignedMediumToBytes(pbb.getPbbMask()));
493         }
494
495         pbbIsidCaseBuilder.setPbbIsid(pbbIsidBuilder.build());
496         matchEntryBuilder.setMatchEntryValue(pbbIsidCaseBuilder.build());
497         matchEntryBuilder.setHasMask(hasmask);
498         return matchEntryBuilder.build();
499     }
500
501     private static MatchEntry toOfMplsTc(final Short mplsTc) {
502         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
503         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
504         matchEntryBuilder.setHasMask(false);
505         matchEntryBuilder.setOxmMatchField(MplsTc.class);
506         MplsTcCaseBuilder mplsTcCaseBuilder = new MplsTcCaseBuilder();
507         MplsTcBuilder mplsTcBuilder = new MplsTcBuilder();
508         mplsTcBuilder.setTc(mplsTc);
509         mplsTcCaseBuilder.setMplsTc(mplsTcBuilder.build());
510         matchEntryBuilder.setMatchEntryValue(mplsTcCaseBuilder.build());
511         return matchEntryBuilder.build();
512     }
513
514     private static MatchEntry toOfMplsBos(final Short mplsBos) {
515         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
516         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
517         matchEntryBuilder.setHasMask(false);
518         matchEntryBuilder.setOxmMatchField(MplsBos.class);
519         MplsBosCaseBuilder mplsBosCaseBuilder = new MplsBosCaseBuilder();
520         MplsBosBuilder mplsBosBuilder = new MplsBosBuilder();
521         mplsBosBuilder.setBos(mplsBos != 0);
522         mplsBosCaseBuilder.setMplsBos(mplsBosBuilder.build());
523         matchEntryBuilder.setMatchEntryValue(mplsBosCaseBuilder.build());
524         return matchEntryBuilder.build();
525     }
526
527     private static MatchEntry toOfMplsLabel(final Long mplsLabel) {
528         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
529         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
530         matchEntryBuilder.setHasMask(false);
531         matchEntryBuilder.setOxmMatchField(MplsLabel.class);
532         MplsLabelCaseBuilder mplsLabelCaseBuilder = new MplsLabelCaseBuilder();
533         MplsLabelBuilder mplsLabelBuilder = new MplsLabelBuilder();
534         mplsLabelBuilder.setMplsLabel(mplsLabel);
535         mplsLabelCaseBuilder.setMplsLabel(mplsLabelBuilder.build());
536         matchEntryBuilder.setMatchEntryValue(mplsLabelCaseBuilder.build());
537         return matchEntryBuilder.build();
538     }
539
540     private static MatchEntry toOfEthernetType(final EthernetType ethernetType) {
541         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
542         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
543         matchEntryBuilder.setHasMask(false);
544         matchEntryBuilder.setOxmMatchField(EthType.class);
545         EthTypeCaseBuilder ethTypeCaseBuilder = new EthTypeCaseBuilder();
546         EthTypeBuilder ethTypeBuilder = new EthTypeBuilder();
547         EtherType etherType = new EtherType(ethernetType.getType().getValue().intValue());
548         ethTypeBuilder.setEthType(etherType);
549         ethTypeCaseBuilder.setEthType(ethTypeBuilder.build());
550         matchEntryBuilder.setMatchEntryValue(ethTypeCaseBuilder.build());
551         return matchEntryBuilder.build();
552     }
553
554     private static MatchEntry toOfIcmpv4Type(final Short icmpv4Type) {
555         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
556         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
557         matchEntryBuilder.setHasMask(false);
558         matchEntryBuilder.setOxmMatchField(Icmpv4Type.class);
559         Icmpv4TypeCaseBuilder icmpv4TypeCaseBuilder = new Icmpv4TypeCaseBuilder();
560         Icmpv4TypeBuilder icmpv4TypeBuilder = new Icmpv4TypeBuilder();
561         icmpv4TypeBuilder.setIcmpv4Type(icmpv4Type);
562         icmpv4TypeCaseBuilder.setIcmpv4Type(icmpv4TypeBuilder.build());
563         matchEntryBuilder.setMatchEntryValue(icmpv4TypeCaseBuilder.build());
564         return matchEntryBuilder.build();
565     }
566
567     private static MatchEntry toOfIcmpv4Code(final Short icmpv4Code) {
568         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
569         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
570         matchEntryBuilder.setHasMask(false);
571         matchEntryBuilder.setOxmMatchField(Icmpv4Code.class);
572         Icmpv4CodeCaseBuilder icmpv4CodeCaseBuilder = new Icmpv4CodeCaseBuilder();
573         Icmpv4CodeBuilder icmpv4CodeBuilder = new Icmpv4CodeBuilder();
574         icmpv4CodeBuilder.setIcmpv4Code(icmpv4Code);
575         icmpv4CodeCaseBuilder.setIcmpv4Code(icmpv4CodeBuilder.build());
576         matchEntryBuilder.setMatchEntryValue(icmpv4CodeCaseBuilder.build());
577         return matchEntryBuilder.build();
578     }
579
580     private static MatchEntry toOfIcmpv6Type(final Short icmpv6Type) {
581         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
582         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
583         matchEntryBuilder.setHasMask(false);
584         matchEntryBuilder.setOxmMatchField(Icmpv6Type.class);
585         Icmpv6TypeCaseBuilder icmpv6TypeCaseBuilder = new Icmpv6TypeCaseBuilder();
586         Icmpv6TypeBuilder icmpv6TypeBuilder = new Icmpv6TypeBuilder();
587         icmpv6TypeBuilder.setIcmpv6Type(icmpv6Type);
588         icmpv6TypeCaseBuilder.setIcmpv6Type(icmpv6TypeBuilder.build());
589         matchEntryBuilder.setMatchEntryValue(icmpv6TypeCaseBuilder.build());
590         return matchEntryBuilder.build();
591     }
592
593     private static MatchEntry toOfIcmpv6Code(final Short icmpv6Code) {
594         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
595         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
596         matchEntryBuilder.setHasMask(false);
597         matchEntryBuilder.setOxmMatchField(Icmpv6Code.class);
598         Icmpv6CodeCaseBuilder icmpv6CodeCaseBuilder = new Icmpv6CodeCaseBuilder();
599         Icmpv6CodeBuilder icmpv6CodeBuilder = new Icmpv6CodeBuilder();
600         icmpv6CodeBuilder.setIcmpv6Code(icmpv6Code);
601         icmpv6CodeCaseBuilder.setIcmpv6Code(icmpv6CodeBuilder.build());
602         matchEntryBuilder.setMatchEntryValue(icmpv6CodeCaseBuilder.build());
603         return matchEntryBuilder.build();
604     }
605
606     private static MatchEntry toOfIpProto(final Short ipProtocol) {
607         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
608         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
609         matchEntryBuilder.setHasMask(false);
610         matchEntryBuilder.setOxmMatchField(IpProto.class);
611         IpProtoCaseBuilder ipProtoCaseBuilder = new IpProtoCaseBuilder();
612         IpProtoBuilder ipProtoBuilder = new IpProtoBuilder();
613         ipProtoBuilder.setProtocolNumber(ipProtocol);
614         ipProtoCaseBuilder.setIpProto(ipProtoBuilder.build());
615         matchEntryBuilder.setMatchEntryValue(ipProtoCaseBuilder.build());
616         return matchEntryBuilder.build();
617     }
618
619     private static MatchEntry toOfIpEcn(final Short ipEcn) {
620         MatchEntryBuilder matchEntryBuilder = new MatchEntryBuilder();
621         matchEntryBuilder.setOxmClass(OpenflowBasicClass.class);
622         matchEntryBuilder.setHasMask(false);
623         matchEntryBuilder.setOxmMatchField(IpEcn.class);
624         IpEcnCaseBuilder ipEcnCaseBuilder = new IpEcnCaseBuilder();
625         IpEcnBuilder ipEcnBuilder = new IpEcnBuilder();
626         ipEcnBuilder.setEcn(ipEcn);
627         ipEcnCaseBuilder.setIpEcn(ipEcnBuilder.build());
628         matchEntryBuilder.setMatchEntryValue(ipEcnCaseBuilder.build());
629         return matchEntryBuilder.build();
630     }
631
632     /**
633      * Create default empty match entries
634      * Use this method, if result from converter is empty.
635      */
636     public static List<MatchEntry> defaultResult() {
637         return FlowConvertor.DEFAULT_MATCH_ENTRIES;
638     }
639
640     @Override
641     public Collection<Class<?>> getTypes() {
642         return TYPES;
643     }
644
645     @Override
646     public List<MatchEntry> convert(final Match source, final VersionConvertorData data) {
647         List<MatchEntry> result = new ArrayList<>();
648
649         if (source == null) {
650             return result;
651         }
652
653         final ExtensionConverterProvider extensionConvertorProvider = OFSessionUtil.getExtensionConvertorProvider();
654
655         inPortMatch(result, source.getInPort());
656         inPhyPortMatch(result, source.getInPhyPort());
657         metadataMatch(result, source.getMetadata());
658         packetTypeMatch(result, source.getPacketTypeMatch());
659         ethernetMatch(result, source.getEthernetMatch());
660         vlanMatch(result, source.getVlanMatch());
661         ipMatch(result, source.getIpMatch());
662         layer4Match(result, source.getLayer4Match(), getConvertorExecutor(), extensionConvertorProvider);
663         icmpv4Match(result, source.getIcmpv4Match());
664         icmpv6Match(result, source.getIcmpv6Match());
665         layer3Match(result, source.getLayer3Match(), getConvertorExecutor(), extensionConvertorProvider);
666         protocolMatchFields(result, source.getProtocolMatchFields());
667         tunnelMatch(result, source.getTunnel());
668         tcpFlagsMatch(result, source.getTcpFlagsMatch());
669
670         /*
671          * TODO: EXTENSION PROPOSAL (source, MD-SAL to OFJava)
672          * - we might need version for conversion and for key
673          */
674         Optional<GeneralExtensionListGrouping> extensionListOpt =
675                 ExtensionResolvers.getMatchExtensionResolver().getExtension(source);
676         if (extensionListOpt.isPresent()) {
677             List<ExtensionList> extensionListList = extensionListOpt.get().getExtensionList();
678             for (ExtensionList extensionItem : extensionListList) {
679                 // TODO: get real version
680                 ConverterExtensionKey<? extends ExtensionKey> key =
681                         new ConverterExtensionKey<>(extensionItem.getExtensionKey(), OFConstants.OFP_VERSION_1_3);
682                 ConvertorToOFJava<MatchEntry> convertor = extensionConvertorProvider.getConverter(key);
683                 if (convertor == null) {
684                     throw new IllegalStateException("No converter found for key: " + key.toString());
685                 }
686                 MatchEntry ofMatch = convertor.convert(extensionItem.getExtension());
687                 result.add(ofMatch);
688             }
689         }
690
691         return result;
692     }
693 }
694