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