/*
* 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;
}
}