Update MRI projects for Aluminium
[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 package org.opendaylight.openflowplugin.impl.protocol.serialization.match;
9
10 import io.netty.buffer.ByteBuf;
11 import java.util.Collection;
12 import java.util.LinkedHashMap;
13 import java.util.Map;
14 import java.util.Optional;
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.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.ExtensionKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.general.rev140714.general.extension.list.grouping.ExtensionList;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 public class MatchSerializer implements OFSerializer<Match>, HeaderSerializer<Match>,
37         MatchEntrySerializerRegistry, SerializerRegistryInjector {
38
39     private static final Logger LOG = LoggerFactory.getLogger(MatchSerializer.class);
40     private static final byte OXM_MATCH_TYPE_CODE = 1;
41     private final Map<org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializerKey,
42             MatchEntrySerializer> entryRegistry = new LinkedHashMap<>();
43     private SerializerRegistry registry;
44
45     @Override
46     public void serialize(final Match match, final ByteBuf outBuffer) {
47         // Save start index in buffer
48         final int matchStartIndex = outBuffer.writerIndex();
49
50         // With OpenflowPlugin models, we cannot check difference between OXM and Standard match type
51         // so all matches will be OXM
52         outBuffer.writeShort(OXM_MATCH_TYPE_CODE);
53
54         // Save length of match type
55         int matchLengthIndex = outBuffer.writerIndex();
56         outBuffer.writeShort(EncodeConstants.EMPTY_LENGTH);
57
58         // Small hack to be able to serialize only match entryRegistry externally
59         serializeHeader(match, outBuffer);
60
61         // Length of ofp_match (excluding padding)
62         int matchLength = outBuffer.writerIndex() - matchStartIndex;
63         outBuffer.setShort(matchLengthIndex, matchLength);
64
65         // If we have any remaining padding, write it at end
66         int paddingRemainder = matchLength % EncodeConstants.PADDING;
67         if (paddingRemainder != 0) {
68             outBuffer.writeZero(EncodeConstants.PADDING - paddingRemainder);
69         }
70     }
71
72     @Override
73     public void serializeHeader(final Match match, final ByteBuf outBuffer) {
74         if (match == null) {
75             LOG.debug("Match is null, skipping serialization of match entries");
76             return;
77         }
78
79         // Serialize match entries
80         entryRegistry.values().forEach(value -> value.serializeIfPresent(match, outBuffer));
81
82         // Serialize match extensions
83         ExtensionResolvers
84                 .getMatchExtensionResolver()
85                 .getExtension(match)
86                 .flatMap(extensions -> Optional.ofNullable(extensions.nonnullExtensionList()))
87                 .ifPresent(extensionList -> serializeExtensionList(extensionList.values(), outBuffer));
88     }
89
90     private void serializeExtensionList(final Collection<ExtensionList> extensionList, final ByteBuf outBuffer) {
91         // TODO: Remove also extension converters
92         extensionList.forEach(extension -> {
93             final ConverterExtensionKey<? extends ExtensionKey> converterExtensionKey =
94                     new ConverterExtensionKey<>(extension.getExtensionKey(), OFConstants.OFP_VERSION_1_3);
95
96             Optional.ofNullable(OFSessionUtil.getExtensionConvertorProvider())
97                     .flatMap(provider -> Optional.ofNullable(provider.<MatchEntry>getConverter(converterExtensionKey)))
98                     .map(matchEntryConvertorToOFJava -> {
99                         final MatchEntry entry = matchEntryConvertorToOFJava.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) entry.getMatchEntryValue())
107                                     .getExperimenter().getExperimenter().getValue());
108                         }
109
110                         final OFSerializer<MatchEntry> entrySerializer = registry.getSerializer(key);
111                         entrySerializer.serialize(entry, outBuffer);
112                         return entry;
113                     })
114                     .orElseGet(() -> {
115                         LOG.warn("Serializer for match entry {} for version {} not found.",
116                                 extension.getExtension().implementedInterface(),
117                                 OFConstants.OFP_VERSION_1_3);
118                         return null;
119                     });
120         });
121     }
122
123     @Override
124     public void injectSerializerRegistry(final SerializerRegistry serializerRegistry) {
125         registry = serializerRegistry;
126     }
127
128     @Override
129     public void registerEntrySerializer(
130             final org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializerKey key,
131             final MatchEntrySerializer serializer) {
132         if (key == null || serializer == null) {
133             throw new IllegalArgumentException("MatchEntrySerializerKey or Serializer is null");
134         }
135
136         final MatchEntrySerializer seInRegistry = entryRegistry.put(key, serializer);
137         if (seInRegistry != null) {
138             LOG.debug("Serializer for key {} overwritten. Old serializer: {}, new serializer: {}", key,
139                     seInRegistry.getClass().getName(), serializer.getClass().getName());
140         }
141     }
142
143     @Override
144     public boolean unregisterEntrySerializer(
145             final org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializerKey key) {
146         return entryRegistry.remove(key) != null;
147     }
148 }