Fix comparison of match extensions
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / protocol / serialization / match / MatchSerializer.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
9 package org.opendaylight.openflowplugin.impl.protocol.serialization.match;
10
11 import io.netty.buffer.ByteBuf;
12 import java.util.LinkedHashMap;
13 import java.util.Map;
14 import java.util.Objects;
15 import org.opendaylight.openflowjava.protocol.api.extensibility.HeaderSerializer;
16 import org.opendaylight.openflowjava.protocol.api.extensibility.OFSerializer;
17 import org.opendaylight.openflowjava.protocol.api.extensibility.SerializerRegistry;
18 import org.opendaylight.openflowjava.protocol.api.extensibility.SerializerRegistryInjector;
19 import org.opendaylight.openflowjava.protocol.api.keys.MatchEntrySerializerKey;
20 import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
21 import org.opendaylight.openflowplugin.api.OFConstants;
22 import org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializer;
23 import org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializerRegistry;
24 import org.opendaylight.openflowplugin.extension.api.ConverterExtensionKey;
25 import org.opendaylight.openflowplugin.openflow.md.core.extension.ExtensionResolvers;
26 import org.opendaylight.openflowplugin.openflow.md.core.session.OFSessionUtil;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.augments.rev150225.oxm.container.match.entry.value.ExperimenterIdCase;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.ExperimenterClass;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.oxm.rev150225.match.entries.grouping.MatchEntry;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 public class MatchSerializer implements OFSerializer<Match>, HeaderSerializer<Match>,
35         MatchEntrySerializerRegistry, SerializerRegistryInjector {
36
37     private static final Logger LOG = LoggerFactory.getLogger(MatchSerializer.class);
38     private static final byte OXM_MATCH_TYPE_CODE = 1;
39     private final Map<org.opendaylight.openflowplugin.api.openflow.protocol.serialization.
40             MatchEntrySerializerKey, MatchEntrySerializer> entryRegistry = new LinkedHashMap<>();
41     private SerializerRegistry registry;
42
43     @Override
44     public void serialize(Match match, ByteBuf outBuffer) {
45         if (match == null) {
46             LOG.debug("Match is null");
47             return;
48         }
49
50         // Save start index in buffer
51         int matchStartIndex = outBuffer.writerIndex();
52
53         // With OpenflowPlugin models, we cannot check difference between OXM and Standard match type
54         // so all matches will be OXM
55         outBuffer.writeShort(OXM_MATCH_TYPE_CODE);
56
57         // Save length of match type
58         int matchLengthIndex = outBuffer.writerIndex();
59         outBuffer.writeShort(EncodeConstants.EMPTY_LENGTH);
60
61         // Small hack to be able to serialize only match entryRegistry externally
62         serializeHeader(match, outBuffer);
63
64         // Length of ofp_match (excluding padding)
65         int matchLength = outBuffer.writerIndex() - matchStartIndex;
66         outBuffer.setShort(matchLengthIndex, matchLength);
67
68         // If we have any remaining padding, write it at end
69         int paddingRemainder = matchLength % EncodeConstants.PADDING;
70         if (paddingRemainder != 0) {
71             outBuffer.writeZero(EncodeConstants.PADDING - paddingRemainder);
72         }
73     }
74
75     @Override
76     public void serializeHeader(Match match, ByteBuf outBuffer) {
77         if (match == null) {
78             LOG.debug("Match is null");
79             return;
80         }
81
82         // Serialize match entries
83         entryRegistry.entrySet().forEach(entry -> {
84             if (entry.getValue().matchTypeCheck(match)) {
85                 entry.getValue().serialize(match, outBuffer);
86             }
87         });
88
89         // Serialize match extensions
90         ExtensionResolvers.getMatchExtensionResolver().getExtension(match).map(extensions -> {
91             if (Objects.nonNull(extensions)) {
92                 extensions.getExtensionList().forEach(extension -> {
93                     // TODO: Remove also extension converters
94                     final MatchEntry entry = OFSessionUtil
95                         .getExtensionConvertorProvider()
96                         .<MatchEntry>getConverter(new ConverterExtensionKey<>(
97                             extension.getExtensionKey(),
98                             OFConstants.OFP_VERSION_1_3))
99                         .convert(extension.getExtension());
100
101                     final MatchEntrySerializerKey<?, ?> key = new MatchEntrySerializerKey<>(
102                         EncodeConstants.OF13_VERSION_ID, entry.getOxmClass(), entry.getOxmMatchField());
103
104                     // If entry is experimenter, set experimenter ID to key
105                     if (entry.getOxmClass().equals(ExperimenterClass.class)) {
106                         key.setExperimenterId(ExperimenterIdCase.class.cast(entry.getMatchEntryValue())
107                             .getExperimenter().getExperimenter().getValue());
108                     }
109
110                     final OFSerializer<MatchEntry> entrySerializer = registry.getSerializer(key);
111                     entrySerializer.serialize(entry, outBuffer);
112                 });
113             }
114
115             return extensions;
116         });
117     }
118
119     @Override
120     public void injectSerializerRegistry(SerializerRegistry serializerRegistry) {
121         registry = serializerRegistry;
122     }
123
124     @Override
125     public void registerEntrySerializer(org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializerKey key, MatchEntrySerializer serializer) {
126         if (Objects.isNull(key) || Objects.isNull(serializer)) {
127             throw new IllegalArgumentException("MatchEntrySerializerKey or Serializer is null");
128         }
129
130         final MatchEntrySerializer seInRegistry = entryRegistry.put(key, serializer);
131         if (seInRegistry != null) {
132             LOG.debug("Serializer for key {} overwritten. Old serializer: {}, new serializer: {}", key,
133                     seInRegistry.getClass().getName(), serializer.getClass().getName());
134         }
135     }
136
137     @Override
138     public boolean unregisterEntrySerializer(org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializerKey key) {
139         return Objects.nonNull(entryRegistry.remove(key));
140     }
141 }