--- /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.serialization;
+
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFSerializer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
+
+public interface MatchEntrySerializer extends OFSerializer<Match> {
+
+ /**
+ * Checks if current match is this match type
+ * @param match Openflow match
+ * @return true if matched
+ */
+ boolean matchTypeCheck(final Match match);
+
+}
\ No newline at end of file
--- /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.serialization;
+
+/**
+ * Marker interface - marks keys appropriate for match entry serializer registration
+ */
+public interface MatchEntrySerializerKey {
+}
--- /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.serialization;
+
+public interface MatchEntrySerializerRegistry {
+
+ /**
+ * Registers match entry serializer.
+
+ * @param key used for deserializer lookup
+ * @param serializer serializer instance
+ */
+ void registerEntrySerializer(MatchEntrySerializerKey key, MatchEntrySerializer serializer);
+
+ /**
+ * Unregisters match entry serializer
+ * @param key used for serializer lookup
+ * @return true if serializer was removed, false if no serializer was found under specified key
+ */
+ boolean unregisterEntrySerializer(MatchEntrySerializerKey key);
+
+}
--- /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.serialization;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import org.opendaylight.openflowjava.protocol.api.extensibility.SerializerExtensionProvider;
+import org.opendaylight.openflowjava.protocol.api.keys.MessageTypeKey;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializer;
+import org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializerRegistry;
+import org.opendaylight.openflowplugin.impl.protocol.serialization.match.MatchEntrySerializerKeyImpl;
+import org.opendaylight.openflowplugin.impl.protocol.serialization.match.MatchSerializer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
+
+/**
+ * Util class for injecting new match serializers into OpenflowJava
+ */
+public class MatchSerializerInjector {
+
+ /**
+ * Injects match serializers into provided {@link org.opendaylight.openflowjava.protocol.api.extensibility.SerializerExtensionProvider}
+ * @param provider OpenflowJava serializer extension provider
+ */
+ public static void injectSerializers(final SerializerExtensionProvider provider) {
+ final MatchSerializer serializer = new MatchSerializer();
+ provider.registerSerializer(
+ new MessageTypeKey<>(EncodeConstants.OF13_VERSION_ID, Match.class),
+ serializer);
+
+ // Inject all match entry serializers to match serializers using injector created by createInjector method
+ final Function<Integer, Function<Integer, Consumer<MatchEntrySerializer>>> injector =
+ createInjector(serializer, EncodeConstants.OF13_VERSION_ID);
+ }
+
+ /**
+ * Create injector that will inject new match entry serializers into #{@link org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializerRegistry}
+ * @param registry Match entry serializer registry
+ * @param version Openflow version
+ * @return injector
+ */
+ @VisibleForTesting
+ static Function<Integer, Function<Integer, Consumer<MatchEntrySerializer>>> createInjector(
+ final MatchEntrySerializerRegistry registry,
+ final byte version) {
+ return oxmClass -> oxmField -> serializer ->
+ registry.registerEntrySerializer(
+ new MatchEntrySerializerKeyImpl(version, oxmClass, oxmField),
+ serializer);
+ }
+}
*/
public static void injectSerializers(final SerializerExtensionProvider provider) {
// Inject new serializers here
+ MatchSerializerInjector.injectSerializers(provider);
MessageSerializerInjector.injectSerializers(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.serialization.match;
+
+import io.netty.buffer.ByteBuf;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
+
+public abstract class AbstractExperimenterMatchEntrySerializer extends AbstractMatchEntrySerializer {
+
+ @Override
+ public void serialize(Match match, ByteBuf outBuffer) {
+ super.serialize(match, outBuffer);
+ outBuffer.writeInt(Long.valueOf(getExperimenterId()).intValue());
+ }
+
+ @Override
+ public void serializeHeader(Match match, ByteBuf outBuffer) {
+ outBuffer.writeShort(getOxmClassCode());
+
+ int fieldAndMask = getOxmFieldCode() << 1;
+ int length = getValueLength();
+
+ if (getHasMask(match)) {
+ fieldAndMask |= 1;
+ length *= 2;
+ }
+
+ outBuffer.writeByte(fieldAndMask);
+
+ // Add length of experimenter ID to total length
+ outBuffer.writeByte(length + EncodeConstants.SIZE_OF_INT_IN_BYTES);
+ }
+
+ /**
+ * @return experimenter match entry id
+ */
+ protected abstract long getExperimenterId();
+}
--- /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.serialization.match;
+
+import io.netty.buffer.ByteBuf;
+import java.util.Iterator;
+import java.util.Optional;
+import org.opendaylight.openflowjava.protocol.api.extensibility.HeaderSerializer;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializer;
+import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.IpConversionUtil;
+import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.match.MatchConvertorUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
+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.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.IetfYangUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
+
+public abstract class AbstractMatchEntrySerializer implements HeaderSerializer<Match>, MatchEntrySerializer {
+
+ @Override
+ public void serialize(Match match, ByteBuf outBuffer) {
+ serializeHeader(match, outBuffer);
+ }
+
+ @Override
+ public void serializeHeader(Match match, ByteBuf outBuffer) {
+ outBuffer.writeShort(getOxmClassCode());
+
+ int fieldAndMask = getOxmFieldCode() << 1;
+ int length = getValueLength();
+
+ if (getHasMask(match)) {
+ fieldAndMask |= 1;
+ length *= 2;
+ }
+
+ outBuffer.writeByte(fieldAndMask);
+ outBuffer.writeByte(length);
+ }
+
+ /**
+ * Serialize byte mask to bytes. checking for mask length
+ * @param mask byte mask
+ * @param outBuffer output buffer
+ * @param length mask length
+ */
+ protected static void writeMask(byte[] mask, ByteBuf outBuffer, int length) {
+ if (mask != null && mask.length != length) {
+ throw new IllegalArgumentException("incorrect length of mask: "+
+ mask.length + ", expected: " + length);
+ }
+
+ outBuffer.writeBytes(mask);
+ }
+
+ /**
+ * Serialize Ipv4 address to bytes
+ * @param address Ipv4 address
+ * @param outBuffer output buffer
+ */
+ protected static void writeIpv4Address(final Ipv4Address address, final ByteBuf outBuffer) {
+ outBuffer.writeBytes(IetfInetUtil.INSTANCE.ipv4AddressBytes(address));
+ }
+
+ /**
+ * Serialize Ipv6 address to bytes
+ * @param address Ipv6 address
+ * @param outBuffer output buffer
+ */
+ protected static void writeIpv6Address(final Ipv6Address address, final ByteBuf outBuffer) {
+ outBuffer.writeBytes(IetfInetUtil.INSTANCE.ipv6AddressBytes(address));
+ }
+
+ /**
+ * Serialize Mac address to bytes
+ * @param address Mac address
+ * @param outBuffer output buffer
+ */
+ protected static void writeMacAddress(final MacAddress address, final ByteBuf outBuffer) {
+ outBuffer.writeBytes(IetfYangUtil.INSTANCE.bytesFor(address)); // 48 b + mask [OF 1.3.2 spec]
+ }
+
+ /**
+ * Serialize Ipv4 prefix (address and mask)
+ * @param prefix Ipv4 prefix
+ * @param outBuffer output buffer
+ */
+ protected static void writeIpv4Prefix(final Ipv4Prefix prefix, final ByteBuf outBuffer) {
+ // Split address to IP and mask
+ final Iterator<String> addressParts = IpConversionUtil.splitToParts(prefix);
+
+ // Write address part of prefix
+ writeIpv4Address(new Ipv4Address(addressParts.next()), outBuffer);
+
+ // If prefix had mask, also write prefix
+ Optional.ofNullable(MatchConvertorUtil.extractIpv4Mask(addressParts)).ifPresent(mask ->
+ writeMask(mask, outBuffer, EncodeConstants.GROUPS_IN_IPV4_ADDRESS));
+ }
+
+ /**
+ * Serialize Ipv6 prefix (address and mask)
+ * @param prefix Ipv6 prefix
+ * @param outBuffer output buffer
+ */
+ protected static void writeIpv6Prefix(final Ipv6Prefix prefix, final ByteBuf outBuffer) {
+ // Write address part of prefix
+ writeIpv6Address(IpConversionUtil.extractIpv6Address(prefix), outBuffer);
+
+ // If prefix had mask, also write prefix
+ Optional.ofNullable(IpConversionUtil.extractIpv6Prefix(prefix)).ifPresent(mask ->
+ writeMask(IpConversionUtil.convertIpv6PrefixToByteArray(mask), outBuffer,
+ EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES));
+ }
+
+ /**
+ * @param match Openflow match
+ * @return if field has or has not mask
+ */
+ protected abstract boolean getHasMask(final Match match);
+
+ /**
+ * @return numeric representation of oxm_field
+ */
+ protected abstract int getOxmFieldCode();
+
+ /**
+ * @return numeric representation of oxm_class
+ */
+ protected abstract int getOxmClassCode();
+
+ /**
+ * @return match entry value length (without mask length)
+ */
+ protected abstract int getValueLength();
+}
--- /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.serialization.match;
+
+import org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializerKey;
+
+public class MatchEntrySerializerKeyImpl implements MatchEntrySerializerKey {
+
+ private final short version;
+ private final int oxmClass;
+ private final int oxmField;
+
+ /**
+ * Create new instance of MatchEntrySerializerKeyImpl
+ * @param version openflow version
+ * @param oxmClass match entry oxm class
+ * @param oxmField match entry field code
+ */
+ public MatchEntrySerializerKeyImpl(final short version, final int oxmClass, final int oxmField) {
+ this.version = version;
+ this.oxmClass = oxmClass;
+ this.oxmField = oxmField;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + oxmClass;
+ result = prime * result + oxmField;
+ result = prime * result + version;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null) {
+ return false;
+ }
+
+ if (!(obj instanceof MatchEntrySerializerKeyImpl)) {
+ return false;
+ }
+
+ final MatchEntrySerializerKeyImpl other = (MatchEntrySerializerKeyImpl) obj;
+
+
+ return oxmClass == other.oxmClass
+ && oxmField == other.oxmField
+ && version == other.version;
+ }
+
+
+ @Override
+ public String toString() {
+ return "version: " + version
+ + " oxmClass:" + oxmClass
+ + " oxmField: " + oxmField;
+ }
+
+}
--- /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.serialization.match;
+
+import io.netty.buffer.ByteBuf;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+import org.opendaylight.openflowjava.protocol.api.extensibility.HeaderSerializer;
+import org.opendaylight.openflowjava.protocol.api.extensibility.OFSerializer;
+import org.opendaylight.openflowjava.protocol.api.extensibility.SerializerRegistry;
+import org.opendaylight.openflowjava.protocol.api.extensibility.SerializerRegistryInjector;
+import org.opendaylight.openflowjava.protocol.api.keys.MatchEntrySerializerKey;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializer;
+import org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializerRegistry;
+import org.opendaylight.openflowplugin.extension.api.ConverterExtensionKey;
+import org.opendaylight.openflowplugin.openflow.md.core.extension.ExtensionResolvers;
+import org.opendaylight.openflowplugin.openflow.md.core.session.OFSessionUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev150225.oxm.container.match.entry.value.ExperimenterIdCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.ExperimenterClass;
+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 MatchSerializer implements OFSerializer<Match>, HeaderSerializer<Match>,
+ MatchEntrySerializerRegistry, SerializerRegistryInjector {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MatchSerializer.class);
+ private static final byte OXM_MATCH_TYPE_CODE = 1;
+ private final Map<org.opendaylight.openflowplugin.api.openflow.protocol.serialization.
+ MatchEntrySerializerKey, MatchEntrySerializer> entryRegistry = new LinkedHashMap<>();
+ private SerializerRegistry registry;
+
+ @Override
+ public void serialize(Match match, ByteBuf outBuffer) {
+ if (match == null) {
+ LOG.debug("Match is null");
+ return;
+ }
+
+ // Save start index in buffer
+ int matchStartIndex = outBuffer.writerIndex();
+
+ // With OpenflowPlugin models, we cannot check difference between OXM and Standard match type
+ // so all matches will be OXM
+ outBuffer.writeShort(OXM_MATCH_TYPE_CODE);
+
+ // Save length of match type
+ int matchLengthIndex = outBuffer.writerIndex();
+ outBuffer.writeShort(EncodeConstants.EMPTY_LENGTH);
+
+ // Small hack to be able to serialize only match entryRegistry externally
+ serializeHeader(match, outBuffer);
+
+ // Length of ofp_match (excluding padding)
+ int matchLength = outBuffer.writerIndex() - matchStartIndex;
+ outBuffer.setShort(matchLengthIndex, matchLength);
+
+ // If we have any remaining padding, write it at end
+ int paddingRemainder = matchLength % EncodeConstants.PADDING;
+ if (paddingRemainder != 0) {
+ outBuffer.writeZero(EncodeConstants.PADDING - paddingRemainder);
+ }
+ }
+
+ @Override
+ public void serializeHeader(Match match, ByteBuf outBuffer) {
+ if (match == null) {
+ LOG.debug("Match is null");
+ return;
+ }
+
+ // Serialize match entries
+ entryRegistry.values().stream()
+ .filter(entry -> entry.matchTypeCheck(match))
+ .forEach(entry -> entry.serialize(match, outBuffer));
+
+ // Serialize match extensions
+ ExtensionResolvers.getMatchExtensionResolver().getExtension(match).transform(extensions -> {
+ if (Objects.nonNull(extensions)) {
+ extensions.getExtensionList().forEach(extension-> {
+ // TODO: Remove also extension converters
+ final MatchEntry entry = OFSessionUtil
+ .getExtensionConvertorProvider()
+ .<MatchEntry>getConverter(new ConverterExtensionKey<>(
+ extension.getExtensionKey(),
+ OFConstants.OFP_VERSION_1_3))
+ .convert(extension.getExtension());
+
+ final MatchEntrySerializerKey<?, ?> key = new MatchEntrySerializerKey<>(
+ EncodeConstants.OF13_VERSION_ID, entry.getOxmClass(), entry.getOxmMatchField());
+
+ // If entry is experimenter, set experimenter ID to key
+ if (entry.getOxmClass().equals(ExperimenterClass.class)) {
+ key.setExperimenterId(ExperimenterIdCase.class.cast(entry.getMatchEntryValue())
+ .getExperimenter().getExperimenter().getValue());
+ }
+
+ final OFSerializer<MatchEntry> entrySerializer = registry.getSerializer(key);
+ entrySerializer.serialize(entry, outBuffer);
+ });
+ }
+
+ return extensions;
+ });
+ }
+
+ @Override
+ public void injectSerializerRegistry(SerializerRegistry serializerRegistry) {
+ registry = serializerRegistry;
+ }
+
+ @Override
+ public void registerEntrySerializer(org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializerKey key, MatchEntrySerializer serializer) {
+ if (Objects.isNull(key) || Objects.isNull(serializer)) {
+ throw new IllegalArgumentException("MatchEntrySerializerKey or Serializer is null");
+ }
+
+ final MatchEntrySerializer seInRegistry = entryRegistry.put(key, serializer);
+ if (seInRegistry != null) {
+ LOG.debug("Serializer for key {} overwritten. Old serializer: {}, new serializer: {}", key,
+ seInRegistry.getClass().getName(), serializer.getClass().getName());
+ }
+ }
+
+ @Override
+ public boolean unregisterEntrySerializer(org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializerKey key) {
+ return Objects.nonNull(entryRegistry.remove(key));
+ }
+}
--- /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.serialization.match;
+
+import static org.junit.Assert.assertEquals;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.UnpooledByteBufAllocator;
+import java.util.function.Consumer;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
+
+public abstract class AbstractExperimenterMatchEntrySerializerTest extends AbstractMatchEntrySerializerTest {
+
+ protected void assertMatch(final Match match, final boolean hasMask, final Consumer<ByteBuf> assertBody) throws Exception {
+ final ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.buffer();
+ getSerializer().serialize(match, buffer);
+
+ final int length = (hasMask ? 2 : 1) * getLength();
+ final int lengthExp = length + EncodeConstants.SIZE_OF_INT_IN_BYTES; // add length of Experimenter ID
+
+ assertEquals(buffer.readShort(), 1); // OXM_MATCH_TYPE
+ assertEquals(buffer.readShort(), // Total length of match
+ EncodeConstants.SIZE_OF_SHORT_IN_BYTES // OXM_MATCH_TYPE length
+ + EncodeConstants.SIZE_OF_SHORT_IN_BYTES // LENGTH length
+ + EncodeConstants.SIZE_OF_SHORT_IN_BYTES // OXM_CLASS_CODE length
+ + EncodeConstants.SIZE_OF_BYTE_IN_BYTES // OXM field and mask length
+ + EncodeConstants.SIZE_OF_BYTE_IN_BYTES // OXM field and mask length length
+ + lengthExp // length of data in match entry
+ );
+
+ assertEquals(buffer.readUnsignedShort(), getOxmClassCode());
+ final short fieldAndMask = buffer.readUnsignedByte();
+ assertEquals(getOxmFieldCode(), fieldAndMask >>> 1);
+ assertEquals(hasMask, (fieldAndMask & 1) != 0);
+ assertEquals(buffer.readUnsignedByte(), lengthExp);
+ assertEquals(buffer.readUnsignedInt(), getExperimenterId());
+ assertBody.accept(buffer);
+
+ int paddingRemainder = lengthExp % EncodeConstants.PADDING;
+
+ if (paddingRemainder != 0) {
+ buffer.skipBytes(EncodeConstants.PADDING - paddingRemainder);
+ }
+
+ assertEquals(buffer.readableBytes(), 0);
+ }
+
+ protected abstract long getExperimenterId();
+
+}
--- /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.serialization.match;
+
+import static org.junit.Assert.assertEquals;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.UnpooledByteBufAllocator;
+import java.util.function.Consumer;
+import org.opendaylight.openflowjava.protocol.api.keys.MessageTypeKey;
+import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
+import org.opendaylight.openflowplugin.impl.protocol.serialization.AbstractSerializerTest;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
+
+public abstract class AbstractMatchEntrySerializerTest extends AbstractSerializerTest {
+ private MatchSerializer serializer;
+
+ @Override
+ protected void init() {
+ serializer = getRegistry().getSerializer(new MessageTypeKey<>(EncodeConstants.OF13_VERSION_ID, Match.class));
+ }
+
+ protected void assertMatch(final Match match, final boolean hasMask, final Consumer<ByteBuf> assertBody) throws Exception {
+ final ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.buffer();
+ serializer.serialize(match, buffer);
+
+ final int length = (hasMask ? 2 : 1) * getLength();
+
+ assertEquals(buffer.readShort(), 1); // OXM_MATCH_TYPE
+ assertEquals(buffer.readShort(), // Total length of match
+ EncodeConstants.SIZE_OF_SHORT_IN_BYTES // OXM_MATCH_TYPE length
+ + EncodeConstants.SIZE_OF_SHORT_IN_BYTES // LENGTH length
+ + EncodeConstants.SIZE_OF_SHORT_IN_BYTES // OXM_CLASS_CODE length
+ + EncodeConstants.SIZE_OF_BYTE_IN_BYTES // OXM field and mask length
+ + EncodeConstants.SIZE_OF_BYTE_IN_BYTES // OXM field and mask length length
+ + length // length of data in match entry
+ );
+
+ assertEquals(buffer.readUnsignedShort(), getOxmClassCode());
+ final short fieldAndMask = buffer.readUnsignedByte();
+ assertEquals(getOxmFieldCode(), fieldAndMask >>> 1);
+ assertEquals(hasMask, (fieldAndMask & 1) != 0);
+ assertEquals(buffer.readUnsignedByte(), length);
+ assertBody.accept(buffer);
+
+ int paddingRemainder = length % EncodeConstants.PADDING;
+
+ if (paddingRemainder != 0) {
+ buffer.skipBytes(EncodeConstants.PADDING - paddingRemainder);
+ }
+
+ assertEquals(buffer.readableBytes(), 0);
+ }
+
+ protected MatchSerializer getSerializer() {
+ return serializer;
+ }
+
+ protected abstract int getOxmFieldCode();
+ protected abstract int getOxmClassCode();
+ protected abstract short getLength();
+
+}
\ No newline at end of file