2fcf00cee3c1db187b53d0cb0c968be391627ec7
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / protocol / deserialization / match / MatchDeserializer.java
1 /*
2  * Copyright (c) 2016 Pantheon Technologies s.r.o. 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.impl.protocol.deserialization.match;
9
10 import io.netty.buffer.ByteBuf;
11 import java.util.HashMap;
12 import java.util.Map;
13 import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistry;
14 import org.opendaylight.openflowjava.protocol.api.extensibility.DeserializerRegistryInjector;
15 import org.opendaylight.openflowjava.protocol.api.extensibility.HeaderDeserializer;
16 import org.opendaylight.openflowjava.protocol.api.extensibility.OFDeserializer;
17 import org.opendaylight.openflowjava.protocol.api.keys.MatchEntryDeserializerKey;
18 import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
19 import org.opendaylight.openflowplugin.api.openflow.protocol.deserialization.MatchEntryDeserializer;
20 import org.opendaylight.openflowplugin.api.openflow.protocol.deserialization.MatchEntryDeserializerRegistry;
21 import org.opendaylight.openflowplugin.extension.api.path.MatchPath;
22 import org.opendaylight.openflowplugin.openflow.md.core.extension.MatchExtensionHelper;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntry;
26 import org.opendaylight.yangtools.yang.common.Uint32;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 public class MatchDeserializer implements OFDeserializer<Match>, HeaderDeserializer<Match>,
31         MatchEntryDeserializerRegistry, MatchEntryDeserializer, DeserializerRegistryInjector {
32
33     private static final Logger LOG = LoggerFactory.getLogger(MatchDeserializer.class);
34     private final Map<MatchEntryDeserializerKey, MatchEntryDeserializer> entryRegistry = new HashMap<>();
35     private final MatchPath matchPath;
36     private DeserializerRegistry registry;
37
38     public MatchDeserializer(final MatchPath matchPath) {
39         this.matchPath = matchPath;
40     }
41
42     @Override
43     public Match deserialize(final ByteBuf inBuffer) {
44         if (inBuffer.readableBytes() <= 0) {
45             return null;
46         }
47
48         final MatchBuilder builder = new MatchBuilder();
49
50         // OFP do not have any method to differentiate between OXM and standard match, so we do not care about type
51         inBuffer.readUnsignedShort();
52         final int length = inBuffer.readUnsignedShort();
53
54         final int startIndex = inBuffer.readerIndex();
55         final int entriesLength = length - 2 * EncodeConstants.SIZE_OF_SHORT_IN_BYTES;
56
57         while (inBuffer.readerIndex() - startIndex < entriesLength) {
58             deserializeEntry(inBuffer, builder);
59         }
60
61         int paddingRemainder = length % EncodeConstants.PADDING;
62
63         if (paddingRemainder != 0) {
64             inBuffer.skipBytes(EncodeConstants.PADDING - paddingRemainder);
65         }
66
67         return builder.build();
68     }
69
70     @Override
71     public Match deserializeHeader(final ByteBuf inBuffer) {
72         final MatchBuilder builder = new MatchBuilder();
73         deserializeEntry(inBuffer, builder);
74         return builder.build();
75     }
76
77     @Override
78     public void deserializeEntry(final ByteBuf inBuffer, final MatchBuilder builder) {
79         if (inBuffer.readableBytes() <= 0) {
80             return;
81         }
82         int oxmClass = inBuffer.getUnsignedShort(inBuffer.readerIndex());
83         int oxmField = inBuffer.getUnsignedByte(inBuffer.readerIndex()
84                 + EncodeConstants.SIZE_OF_SHORT_IN_BYTES) >>> 1;
85
86         final MatchEntryDeserializerKey key = new MatchEntryDeserializerKey(
87                 EncodeConstants.OF13_VERSION_ID, oxmClass, oxmField);
88
89         if (oxmClass == EncodeConstants.EXPERIMENTER_VALUE) {
90             long expId = inBuffer.getUnsignedInt(inBuffer.readerIndex()
91                     + EncodeConstants.SIZE_OF_SHORT_IN_BYTES
92                     + 2 * EncodeConstants.SIZE_OF_BYTE_IN_BYTES);
93
94             key.setExperimenterId(Uint32.valueOf(expId));
95         }
96
97         final MatchEntryDeserializer entryDeserializer = entryRegistry.get(key);
98
99         if (entryDeserializer != null) {
100             entryDeserializer.deserializeEntry(inBuffer, builder);
101         } else {
102             final OFDeserializer<MatchEntry> deserializer = registry.getDeserializer(key);
103             MatchExtensionHelper.injectExtension(EncodeConstants.OF13_VERSION_ID,
104                     deserializer.deserialize(inBuffer), builder, matchPath);
105         }
106     }
107
108     @Override
109     public void registerEntryDeserializer(final MatchEntryDeserializerKey key,
110             final MatchEntryDeserializer deserializer) {
111         if (key == null || deserializer == null) {
112             throw new IllegalArgumentException("MatchEntryDeserializerKey or Deserializer is null");
113         }
114
115         final MatchEntryDeserializer desInRegistry = entryRegistry.put(key, deserializer);
116
117         if (desInRegistry != null) {
118             LOG.debug("Deserializer for key {} overwritten. Old deserializer: {}, new deserializer: {}", key,
119                     desInRegistry.getClass().getName(), deserializer.getClass().getName());
120         }
121     }
122
123     @Override
124     public boolean unregisterEntryDeserializer(final MatchEntryDeserializerKey key) {
125         if (key == null) {
126             throw new IllegalArgumentException("MatchEntryDeserializerKey is null");
127         }
128
129         return entryRegistry.remove(key) != null;
130     }
131
132     @Override
133     public void injectDeserializerRegistry(final DeserializerRegistry deserializerRegistry) {
134         registry = deserializerRegistry;
135     }
136 }