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