--- /dev/null
+/*
+ * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.api.openflow.protocol.deserialization;
+
+import io.netty.buffer.ByteBuf;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+
+public interface MatchEntryDeserializer {
+
+ /**
+ * Transforms byte match entry message into POJO/DTO (of type E).
+ *
+ * @param message message as bytes in ByteBuf
+ * @param builder match builder
+ */
+ void deserializeEntry(ByteBuf message, MatchBuilder builder);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.api.openflow.protocol.deserialization;
+
+import org.opendaylight.openflowjava.protocol.api.keys.MatchEntryDeserializerKey;
+
+public interface MatchEntryDeserializerRegistry {
+
+ /**
+ * Registers match entry deserializer.
+ *
+ * @param key used for deserializer lookup
+ * @param deserializer deserializer instance
+ */
+ void registerEntryDeserializer(MatchEntryDeserializerKey key, MatchEntryDeserializer deserializer);
+
+ /**
+ * Unregisters match entry deserializer
+ *
+ * @param key used for deserializer lookup
+ * @return true if deserializer was removed, false if no deserializer was found under specified key
+ */
+ boolean unregisterEntryDeserializer(MatchEntryDeserializerKey key);
+
+}
*/
public static void injectDeserializers(final DeserializerExtensionProvider provider) {
// Inject new deserializers here
+ MatchDeserializerInjector.injectDeserializers(provider);
MessageDeserializerInjector.injectDeserializers(provider);
}
}
--- /dev/null
+/*
+ * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerExtensionProvider;
+import org.opendaylight.openflowjava.protocol.api.keys.MatchEntryDeserializerKey;
+import org.opendaylight.openflowjava.protocol.api.keys.MessageCodeKey;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.key.MessageCodeMatchKey;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.match.MatchDeserializer;
+import org.opendaylight.openflowplugin.api.openflow.protocol.deserialization.MatchEntryDeserializer;
+import org.opendaylight.openflowplugin.api.openflow.protocol.deserialization.MatchEntryDeserializerRegistry;
+import org.opendaylight.openflowplugin.extension.api.path.MatchPath;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
+
+/**
+ * Util class for injecting new match entry deserializers into OpenflowJava
+ */
+public class MatchDeserializerInjector {
+
+ /**
+ * Injects deserializers into provided {@link org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerExtensionProvider}
+ * @param provider OpenflowJava deserializer extension provider
+ */
+ public static void injectDeserializers(final DeserializerExtensionProvider provider) {
+ for (MatchPath path : MatchPath.values()) {
+ final MatchDeserializer deserializer = new MatchDeserializer(path);
+ provider.registerDeserializer(
+ new MessageCodeMatchKey(
+ EncodeConstants.OF13_VERSION_ID,
+ EncodeConstants.EMPTY_LENGTH,
+ Match.class,
+ path),
+ deserializer);
+
+ // Inject new match entry serializers here using injector created by createInjector method
+ final Function<Integer, Function<Long, Function<Integer, Consumer<MatchEntryDeserializer>>>> injector =
+ createInjector(deserializer, EncodeConstants.OF13_VERSION_ID);
+ }
+ }
+
+ /**
+ * Create injector that will inject new serializers into {@link org.opendaylight.openflowplugin.api.openflow.protocol.deserialization.MatchEntryDeserializerRegistry}
+ * @param registry Match entry deserializer registry
+ * @param version Openflow version
+ * @return injector
+ */
+ @VisibleForTesting
+ static Function<Integer, Function<Long, Function<Integer, Consumer<MatchEntryDeserializer>>>> createInjector(
+ final MatchEntryDeserializerRegistry registry,
+ final short version
+ ) {
+ return oxmClass -> expId -> oxmField -> deserializer -> {
+ final MatchEntryDeserializerKey key = new MatchEntryDeserializerKey(version, oxmClass, oxmField);
+ key.setExperimenterId(expId);
+ registry.registerEntryDeserializer(key, deserializer);
+ };
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.key;
+
+import java.util.Objects;
+
+import org.opendaylight.openflowjava.protocol.api.keys.MessageCodeKey;
+import org.opendaylight.openflowplugin.extension.api.path.MatchPath;
+
+public class MessageCodeMatchKey extends MessageCodeKey {
+
+ private MatchPath matchPath;
+
+ /**
+ * Constructor
+ * @param version wire protocol version
+ * @param value used as distinguisher (read from binary data / buffer)
+ * @param clazz class of object that is going to be deserialized
+ * @param matchPath match extension path
+ */
+ public MessageCodeMatchKey(short version, int value, Class<?> clazz, MatchPath matchPath) {
+ super(version, value, clazz);
+ this.matchPath = matchPath;
+ }
+
+ public MatchPath getMatchPath() {
+ return this.matchPath;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ return prime * super.hashCode() + (Objects.isNull(matchPath) ? 0 : matchPath.ordinal());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof MessageCodeMatchKey)) {
+ return false;
+ }
+ MessageCodeMatchKey other = (MessageCodeMatchKey) obj;
+ if (matchPath == null) {
+ if (other.matchPath != null) {
+ return false;
+ }
+ } else if (!matchPath.equals(other.matchPath)) {
+ return false;
+ }
+ return super.equals(obj);
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + " matchPath: " + matchPath.name();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.match;
+
+import io.netty.buffer.ByteBuf;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowjava.protocol.impl.deserialization.match.OxmDeserializerHelper;
+import org.opendaylight.openflowjava.util.ByteBufUtils;
+import org.opendaylight.openflowplugin.api.openflow.protocol.deserialization.MatchEntryDeserializer;
+import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.IpConversionUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+
+public abstract class AbstractMatchEntryDeserializer implements MatchEntryDeserializer {
+
+ /**
+ * Processes match entry header and returns if it have mask, or not
+ * @param in input buffer
+ * @return true if match entry has mask, false otherwise
+ */
+ protected static boolean processHeader(ByteBuf in) {
+ in.skipBytes(EncodeConstants.SIZE_OF_SHORT_IN_BYTES); // skip oxm_class
+ boolean hasMask = (in.readUnsignedByte() & 1) != 0;
+ in.skipBytes(EncodeConstants.SIZE_OF_BYTE_IN_BYTES); // skip match entry length
+ return hasMask;
+ }
+
+ /**
+ * Read Ipv4Prefix from message
+ * @param message buffered message
+ * @param hasMask determines if prefix has mask or not
+ * @return IPv4 prefix
+ */
+ protected static Ipv4Prefix readPrefix(ByteBuf message, boolean hasMask) {
+ final Ipv4Address address = ByteBufUtils.readIetfIpv4Address(message);
+ int mask = 32;
+
+ if (hasMask) {
+ mask = IpConversionUtil.countBits(
+ OxmDeserializerHelper.convertMask(message, EncodeConstants.GROUPS_IN_IPV4_ADDRESS));
+ }
+
+ return IpConversionUtil.createPrefix(address, mask);
+ }
+
+ /**
+ * Throw error on malformed match builder input
+ * @param builder match builder
+ * @param propertyName name of property that already containsData
+ */
+ protected static void throwErrorOnMalformed(MatchBuilder builder, String propertyName) {
+ throw new IllegalArgumentException("Match: " + builder.toString() + " is malformed, "
+ + builder + "#" + propertyName + " contains invalid data.");
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.match;
+
+import io.netty.buffer.ByteBuf;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry;
+import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistryInjector;
+import org.opendaylight.openflowjava.protocol.api.extensibility.HeaderDeserializer;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
+import org.opendaylight.openflowjava.protocol.api.keys.MatchEntryDeserializerKey;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowplugin.api.openflow.protocol.deserialization.MatchEntryDeserializer;
+import org.opendaylight.openflowplugin.api.openflow.protocol.deserialization.MatchEntryDeserializerRegistry;
+import org.opendaylight.openflowplugin.extension.api.path.MatchPath;
+import org.opendaylight.openflowplugin.openflow.md.core.extension.MatchExtensionHelper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MatchDeserializer implements OFDeserializer<Match>, HeaderDeserializer<Match>,
+ MatchEntryDeserializerRegistry, MatchEntryDeserializer, DeserializerRegistryInjector {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MatchDeserializer.class);
+ private final Map<MatchEntryDeserializerKey, MatchEntryDeserializer> entryRegistry = new HashMap<>();
+ private final MatchPath matchPath;
+ private DeserializerRegistry registry;
+
+ public MatchDeserializer(final MatchPath matchPath) {
+ this.matchPath = matchPath;
+ }
+
+ @Override
+ public Match deserialize(ByteBuf inBuffer) {
+ if (inBuffer.readableBytes() <= 0) return null;
+
+ final MatchBuilder builder = new MatchBuilder();
+
+ // OFP do not have any method to differentiate between OXM and standard match, so we do not care about type
+ final int type = inBuffer.readUnsignedShort();
+ final int length = inBuffer.readUnsignedShort();
+
+ final int startIndex = inBuffer.readerIndex();
+ final int entriesLength = length - 2 * EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
+
+ while ((inBuffer.readerIndex() - startIndex) < entriesLength) {
+ deserializeEntry(inBuffer, builder);
+ }
+
+ int paddingRemainder = length % EncodeConstants.PADDING;
+
+ if (paddingRemainder != 0) {
+ inBuffer.skipBytes(EncodeConstants.PADDING - paddingRemainder);
+ }
+
+ return builder.build();
+ }
+
+ @Override
+ public Match deserializeHeader(ByteBuf inBuffer) {
+ final MatchBuilder builder = new MatchBuilder();
+ deserializeEntry(inBuffer, builder);
+ return builder.build();
+ }
+
+ @Override
+ public void deserializeEntry(ByteBuf inBuffer, MatchBuilder builder) {
+ if (inBuffer.readableBytes() <= 0) return;
+ int oxmClass = inBuffer.getUnsignedShort(inBuffer.readerIndex());
+ int oxmField = inBuffer.getUnsignedByte(inBuffer.readerIndex()
+ + EncodeConstants.SIZE_OF_SHORT_IN_BYTES) >>> 1;
+
+ final MatchEntryDeserializerKey key = new MatchEntryDeserializerKey(
+ EncodeConstants.OF13_VERSION_ID,oxmClass, oxmField);
+
+ if (oxmClass == EncodeConstants.EXPERIMENTER_VALUE) {
+ long expId = inBuffer.getUnsignedInt(inBuffer.readerIndex()
+ + EncodeConstants.SIZE_OF_SHORT_IN_BYTES
+ + 2 * EncodeConstants.SIZE_OF_BYTE_IN_BYTES);
+
+ key.setExperimenterId(expId);
+ }
+
+ final MatchEntryDeserializer entryDeserializer = entryRegistry.get(key);
+
+ if (Objects.nonNull(entryDeserializer)) {
+ entryDeserializer.deserializeEntry(inBuffer, builder);
+ } else {
+ final OFDeserializer<MatchEntry> deserializer = registry.getDeserializer(key);
+ MatchExtensionHelper.injectExtension(EncodeConstants.OF13_VERSION_ID,
+ deserializer.deserialize(inBuffer), builder, matchPath);
+ }
+ }
+
+ @Override
+ public void registerEntryDeserializer(MatchEntryDeserializerKey key, MatchEntryDeserializer deserializer) {
+ if (Objects.isNull(key) || Objects.isNull(deserializer)) {
+ throw new IllegalArgumentException("MatchEntryDeserializerKey or Deserializer is null");
+ }
+
+ final MatchEntryDeserializer desInRegistry = entryRegistry.put(key, deserializer);
+
+ if (desInRegistry != null) {
+ LOG.debug("Deserializer for key {} overwritten. Old deserializer: {}, new deserializer: {}", key,
+ desInRegistry.getClass().getName(), deserializer.getClass().getName());
+ }
+ }
+
+ @Override
+ public boolean unregisterEntryDeserializer(MatchEntryDeserializerKey key) {
+ if (Objects.isNull(key)) {
+ throw new IllegalArgumentException("MatchEntryDeserializerKey is null");
+ }
+
+ return Objects.nonNull(entryRegistry.remove(key));
+ }
+
+ @Override
+ public void injectDeserializerRegistry(DeserializerRegistry deserializerRegistry) {
+ registry = deserializerRegistry;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.openflowplugin.impl.protocol.deserialization.match;
+
+import io.netty.buffer.ByteBuf;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowplugin.api.openflow.protocol.deserialization.MatchEntryDeserializer;
+import org.opendaylight.openflowplugin.extension.api.path.MatchPath;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.AbstractDeserializerTest;
+import org.opendaylight.openflowplugin.impl.protocol.deserialization.key.MessageCodeMatchKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
+
+public abstract class AbstractMatchEntryDeserializerTest extends AbstractDeserializerTest {
+
+ private MatchEntryDeserializer deserializer;
+
+ @Override
+ protected void init() {
+ deserializer = getRegistry().getDeserializer(new MessageCodeMatchKey(EncodeConstants.OF13_VERSION_ID,
+ EncodeConstants.EMPTY_LENGTH,
+ Match.class,
+ MatchPath.FLOWSSTATISTICSUPDATE_FLOWANDSTATISTICSMAPLIST_MATCH));
+ }
+
+ protected Match deserialize(ByteBuf inBuffer) {
+ final MatchBuilder builder = new MatchBuilder();
+ deserializer.deserializeEntry(inBuffer, builder);
+ return builder.build();
+ }
+
+ protected void writeHeader(ByteBuf inBuffer, boolean hasMask) {
+ inBuffer.writeShort(getOxmClassCode());
+
+ int fieldAndMask = getOxmFieldCode() << 1;
+ int length = getValueLength();
+
+ if (hasMask) {
+ fieldAndMask |= 1;
+ length *= 2;
+ }
+
+ inBuffer.writeByte(fieldAndMask);
+ inBuffer.writeByte(length);
+ }
+
+ protected abstract int getOxmClassCode();
+ protected abstract int getOxmFieldCode();
+ protected abstract int getValueLength();
+
+}
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
import org.opendaylight.openflowjava.protocol.api.keys.MatchEntrySerializerKey;
import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
import org.opendaylight.openflowplugin.extension.api.AugmentTuple;
import org.opendaylight.openflowplugin.extension.api.ExtensionAugment;
import org.opendaylight.openflowplugin.extension.api.path.MatchPath;
import org.opendaylight.openflowplugin.openflow.md.core.session.OFSessionUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.MatchField;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.OxmClassBase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntry;
throw new IllegalAccessError("singleton enforcement");
}
+
+ /**
+ * @param matchEntry match entry
+ * @param ofVersion openflow version
+ * @param matchPath match path
+ */
+ public static <T> void injectExtension(
+ final short ofVersion,
+ final MatchEntry matchEntry,
+ final T matchBuilder,
+ final MatchPath matchPath) {
+
+ final ExtensionListBuilder extBuilder = processExtension(matchEntry, ofVersion, matchPath);
+
+ if (Objects.isNull(extBuilder)) {
+ LOG.warn("Convertor for {} for version {} with match path {} not found.",
+ matchEntry.toString(),
+ ofVersion,
+ matchPath.name());
+ }
+
+
+ switch (matchPath) {
+ case FLOWSSTATISTICSUPDATE_FLOWANDSTATISTICSMAPLIST_MATCH: {
+ final MatchBuilder augMatchBuilder = MatchBuilder.class.cast(matchBuilder);
+
+ final GeneralAugMatchNotifUpdateFlowStatsBuilder builder = Optional
+ .ofNullable(augMatchBuilder.getAugmentation(GeneralAugMatchNotifUpdateFlowStats.class))
+ .map(aug -> new GeneralAugMatchNotifUpdateFlowStatsBuilder(aug))
+ .orElse(new GeneralAugMatchNotifUpdateFlowStatsBuilder().setExtensionList(new ArrayList<>()));
+
+ builder.getExtensionList().add(extBuilder.build());
+ break;
+ }
+ case PACKETRECEIVED_MATCH: {
+ final org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.packet.received
+ .MatchBuilder augMatchBuilder = org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.packet.received
+ .MatchBuilder.class.cast(matchBuilder);
+
+ final GeneralAugMatchNotifPacketInBuilder builder = Optional
+ .ofNullable(augMatchBuilder.getAugmentation(GeneralAugMatchNotifPacketIn.class))
+ .map(aug -> new GeneralAugMatchNotifPacketInBuilder(aug))
+ .orElse(new GeneralAugMatchNotifPacketInBuilder().setExtensionList(new ArrayList<>()));
+
+ builder.getExtensionList().add(extBuilder.build());
+ break;
+ }
+ case SWITCHFLOWREMOVED_MATCH: {
+ final org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.mod.removed
+ .MatchBuilder augMatchBuilder = org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.mod.removed
+ .MatchBuilder.class.cast(matchBuilder);
+
+
+ final GeneralAugMatchNotifSwitchFlowRemovedBuilder builder = Optional
+ .ofNullable(augMatchBuilder.getAugmentation(GeneralAugMatchNotifSwitchFlowRemoved.class))
+ .map(aug -> new GeneralAugMatchNotifSwitchFlowRemovedBuilder(aug))
+ .orElse(new GeneralAugMatchNotifSwitchFlowRemovedBuilder().setExtensionList(new ArrayList<>()));
+
+ builder.getExtensionList().add(extBuilder.build());
+ break;
+ }
+ default:
+ LOG.warn("Match path {} not supported.", matchPath.name());
+ }
+ }
+
/**
* @param matchEntries match entries
* @param ofVersion openflow version
List<ExtensionList> extensionsList = new ArrayList<>();
for (MatchEntry matchEntry : matchEntries) {
- ExtensionListBuilder extensionListBld = processExtension(matchEntry, ofVersion, matchPath);
+ ExtensionListBuilder extensionListBld = processExtension(matchEntry, ofVersion.getVersion(), matchPath);
if (extensionListBld == null) {
continue;
}
* @param matchEntry
* @return
*/
- private static ExtensionListBuilder processExtension(MatchEntry matchEntry, OpenflowVersion ofVersion, MatchPath matchPath) {
+ private static ExtensionListBuilder processExtension(MatchEntry matchEntry, short ofVersion, MatchPath matchPath) {
ExtensionListBuilder extListBld = null;
/** TODO: EXTENSION PROPOSAL (match, OFJava to MD-SAL) */
MatchEntrySerializerKey<? extends OxmClassBase, ? extends MatchField> key = new MatchEntrySerializerKey<>(
- ofVersion.getVersion(), matchEntry.getOxmClass(), matchEntry.getOxmMatchField());
+ ofVersion, matchEntry.getOxmClass(), matchEntry.getOxmMatchField());
if (null != OFSessionUtil.getExtensionConvertorProvider()) {
ConvertorFromOFJava<MatchEntry, MatchPath> convertor = OFSessionUtil.getExtensionConvertorProvider().getConverter(key);
if (convertor != null) {