2 * Copyright (c) 2016 Pantheon Technologies s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.openflowplugin.impl.protocol.serialization.match;
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
13 import io.netty.buffer.ByteBuf;
14 import io.netty.buffer.Unpooled;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.eclipse.jdt.annotation.Nullable;
17 import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
18 import org.opendaylight.openflowplugin.api.openflow.protocol.serialization.MatchEntrySerializer;
19 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.IpConversionUtil;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.IetfYangUtil;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.Match;
30 * Abstract base class for conveniently implementing {@link MatchEntrySerializer}.
32 * @param <E> Match entry type
33 * @param <M> Match entry mask type, use Void a mask is not applicable
35 public abstract class AbstractMatchEntrySerializer<E, M> implements MatchEntrySerializer {
37 * Base class supporting writing out a particular match entry's header. This class should be subclassed only
38 * in case the header contents depends on the match entry content in a more dynamic fashion than the presence
39 * or absence of the mask. In all other cases using {@link ConstantHeaderWriter} is preferable.
41 * @param <E> Match entry type
42 * @param <M> Match entry mask type, use Void a mask is not applicable
44 protected abstract static class HeaderWriter<E, M> {
47 * Write out the header for a particular entry, containing specified mask, to the provided output buffer.
49 * @param entry match entry for which to write the header
50 * @param mask mask as extracted from the match entry, may be null
51 * @param outBuffer output buffer
53 protected abstract void writeHeader(@NonNull E entry, @Nullable M mask, @NonNull ByteBuf outBuffer);
55 protected static final void writeHeader(final int oxmClassCode, final int oxmFieldCode, final int valueLength,
56 final boolean hasMask, final ByteBuf outBuffer) {
57 writeHeader(oxmClassCode, oxmFieldCode, valueLength, hasMask, 0, outBuffer);
60 protected static final void writeHeader(final int oxmClassCode, final int oxmFieldCode, final int valueLength,
61 final boolean hasMask, final int extraLength, final ByteBuf outBuffer) {
62 outBuffer.writeShort(oxmClassCode);
64 int fieldAndMask = oxmFieldCode << 1;
65 int length = valueLength;
72 outBuffer.writeByte(fieldAndMask);
73 outBuffer.writeByte(length + extraLength);
78 * Utility {@link HeaderWriter} optimized for cases where the header does not depend on the actual entry content
79 * beyond presence/absence of a mask. This class pre-computes the possible header values for masked/unmasked cases
80 * and stores them internally for reuse.
82 * @param <E> Match entry type
83 * @param <M> Match entry mask type, use Void a mask is not applicable
86 * Implementation note:
88 * While it looks like we could save some memory by refactoring this class into two instances for the non-mask
89 * and mask values, that actually would result in increased memory footprint because the JVM object header is
90 * larger than the state we keep. We would also require another reference field in the serializer itself, which
91 * would expand the size of that object, negating the benefit.
93 * Another refactor would see the case where an entry cannot have a mask split out into a separate class, making
94 * that specialized object smaller and not contain the null check in writeHeader(). This can be considered, but
95 * has to be thoroughly benchmarked with representative data, because introducing another implementation means
96 * calls to writeHeader() are no longer monomorphic and are not as readily devirtualizable -- which has performance
97 * implications which can easily negate any behefits from the specialization.
99 protected static final class ConstantHeaderWriter<E, M> extends HeaderWriter<E, M> {
100 private final int withMask;
101 private final int withoutMask;
103 protected ConstantHeaderWriter(final int withMask, final int withoutMask) {
104 this.withMask = withMask;
105 this.withoutMask = withoutMask;
108 protected ConstantHeaderWriter(final int oxmClassCode, final int oxmFieldCode, final int valueLength) {
109 this(oxmClassCode, oxmFieldCode, valueLength, 0);
112 protected ConstantHeaderWriter(final int oxmClassCode, final int oxmFieldCode, final int valueLength,
113 final int extraLength) {
114 this(constructHeader(oxmClassCode, oxmFieldCode, valueLength, extraLength, true),
115 constructHeader(oxmClassCode, oxmFieldCode, valueLength, extraLength, false));
119 protected void writeHeader(final E entry, final M mask, final ByteBuf outBuffer) {
120 outBuffer.writeInt(mask != null ? withMask : withoutMask);
123 private static int constructHeader(final int oxmClassCode, final int oxmFieldCode, final int valueLength,
124 final int extraLength, final boolean withMask) {
125 final ByteBuf buf = Unpooled.buffer();
126 writeHeader(oxmClassCode, oxmFieldCode, valueLength, withMask, extraLength, buf);
127 final int header = buf.readInt();
128 verify(buf.readableBytes() == 0);
133 private final HeaderWriter<E, M> headerWriter;
135 protected AbstractMatchEntrySerializer(final HeaderWriter<E, M> headerWriter) {
136 this.headerWriter = requireNonNull(headerWriter);
139 protected AbstractMatchEntrySerializer(final int oxmClassCode, final int oxmFieldCode, final int valueLength) {
140 this(new ConstantHeaderWriter<>(oxmClassCode, oxmFieldCode, valueLength));
144 public final void serializeIfPresent(final Match match, final ByteBuf outBuffer) {
145 final E entry = extractEntry(match);
147 final M mask = extractEntryMask(entry);
148 headerWriter.writeHeader(entry, mask, outBuffer);
149 serializeEntry(entry, mask, outBuffer);
154 * Serialize byte mask to bytes. checking for mask length.
156 * @param mask byte mask
157 * @param outBuffer output buffer
158 * @param length mask length
160 protected static void writeMask(final byte[] mask, final ByteBuf outBuffer, final int length) {
162 if (mask.length != length) {
163 throw new IllegalArgumentException("incorrect length of mask: " + mask.length + ", expected: "
166 outBuffer.writeBytes(mask);
171 * Serialize Ipv4 address to bytes.
173 * @param address Ipv4 address
174 * @param outBuffer output buffer
176 protected static void writeIpv4Address(final Ipv4Address address, final ByteBuf outBuffer) {
177 outBuffer.writeBytes(IetfInetUtil.ipv4AddressBytes(address));
181 * Serialize Ipv6 address to bytes.
183 * @param address Ipv6 address
184 * @param outBuffer output buffer
186 protected static void writeIpv6Address(final Ipv6Address address, final ByteBuf outBuffer) {
187 outBuffer.writeBytes(IetfInetUtil.ipv6AddressBytes(address));
191 * Serialize Mac address to bytes.
193 * @param address Mac address
194 * @param outBuffer output buffer
196 protected static void writeMacAddress(final MacAddress address, final ByteBuf outBuffer) {
197 // 48 b + mask [OF 1.3.2 spec]
198 outBuffer.writeBytes(IetfYangUtil.macAddressBytes(address));
202 * Serialize Ipv4 prefix (address and mask).
204 * @param prefix Ipv4 prefix
205 * @param outBuffer output buffer
207 protected static void writeIpv4Prefix(final @NonNull Ipv4Prefix prefix, final @Nullable Integer mask,
208 final @NonNull ByteBuf outBuffer) {
209 // Write address part of prefix
210 writeIpv4Address(IetfInetUtil.ipv4AddressFrom(prefix), outBuffer);
212 // If prefix had mask, also write prefix
214 outBuffer.writeInt(IpConversionUtil.maskForIpv4Prefix(mask));
219 * Serialize Ipv6 prefix (address and mask).
221 * @param prefix Ipv6 prefix
222 * @param outBuffer output buffer
224 protected static void writeIpv6Prefix(final @NonNull Ipv6Prefix prefix, final @Nullable Integer mask,
225 final @NonNull ByteBuf outBuffer) {
226 // Write address part of prefix
227 writeIpv6Address(IpConversionUtil.extractIpv6Address(prefix), outBuffer);
229 // If prefix had mask, also write prefix
231 writeMask(IpConversionUtil.convertIpv6PrefixToByteArray(mask), outBuffer,
232 EncodeConstants.SIZE_OF_IPV6_ADDRESS_IN_BYTES);
237 * Extract the corresponding entry from a match.
239 * @param match Openflow match
240 * @return Entry, null if not present
242 protected abstract @Nullable E extractEntry(Match match);
245 * Extract the mask contained in an entry.
247 * @param entry entry to examine
248 * @return Mask, null if not present
250 protected abstract @Nullable M extractEntryMask(@NonNull E entry);
253 * Extract the corresponding entry from a match.
255 * @param entry entry to serialize
256 * @param mask mask as extracted from entry
257 * @param outBuffer output buffer
259 protected abstract void serializeEntry(@NonNull E entry, @Nullable M mask, @NonNull ByteBuf outBuffer);