Clean up MatchNormalizationUtil
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / util / MatchNormalizationUtil.java
1 /*
2  * Copyright (c) 2017 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.util;
9
10 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeIpv4Arbitrary;
11 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeIpv4Prefix;
12 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeIpv6AddressWithoutMask;
13 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeIpv6Arbitrary;
14 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeIpv6Prefix;
15 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeMacAddress;
16 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeMacAddressMask;
17 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeProtocolAgnosticPort;
18
19 import com.google.common.annotations.VisibleForTesting;
20 import com.google.common.cache.CacheBuilder;
21 import com.google.common.cache.CacheLoader;
22 import com.google.common.cache.LoadingCache;
23 import com.google.common.collect.ImmutableMap;
24 import com.google.common.collect.ImmutableSet;
25 import java.util.function.Function;
26 import java.util.stream.Stream;
27 import org.eclipse.jdt.annotation.NonNull;
28 import org.opendaylight.openflowplugin.api.OFConstants;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpSourceHardwareAddressBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpTargetHardwareAddressBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetSourceBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatch;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchArbitraryBitMask;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6Match;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchArbitraryBitMask;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.TunnelIpv4Match;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.TunnelIpv4MatchBuilder;
47 import org.opendaylight.yangtools.yang.common.Uint8;
48
49 /**
50  * Utility class for match normalization.
51  */
52 public final class MatchNormalizationUtil {
53     // Cache normalizers for common OpenFlow versions
54     private static final ImmutableMap<Uint8, ImmutableSet<Function<MatchBuilder, MatchBuilder>>> COMMON_NORMALIZERS =
55         ImmutableMap.<Uint8, ImmutableSet<Function<MatchBuilder, MatchBuilder>>>builder()
56             .put(OFConstants.OFP_VERSION_1_0,
57                 createNormalizers(OFConstants.OFP_VERSION_1_0).collect(ImmutableSet.toImmutableSet()))
58             .put(OFConstants.OFP_VERSION_1_3,
59                 createNormalizers(OFConstants.OFP_VERSION_1_3).collect(ImmutableSet.toImmutableSet()))
60             .build();
61     private static final LoadingCache<Uint8, ImmutableSet<Function<MatchBuilder, MatchBuilder>>> UNCOMMON_NORMALIZERS =
62         CacheBuilder.newBuilder().weakValues().build(new CacheLoader<>() {
63             @Override
64             public ImmutableSet<Function<MatchBuilder, MatchBuilder>> load(final Uint8 key) {
65                 return createNormalizers(key).collect(ImmutableSet.toImmutableSet());
66             }
67         });
68
69     private MatchNormalizationUtil() {
70         // Hidden on purpose
71     }
72
73     /**
74      * Normalize match.
75      *
76      * @param match   the OpenFlow match
77      * @param version the OpenFlow version
78      * @return normalized OpenFlow match
79      */
80     public static @NonNull Match normalizeMatch(@NonNull final Match match, final Uint8 version) {
81         final var matchBuilder = new MatchBuilder(match);
82
83         var normalizers = COMMON_NORMALIZERS.get(version);
84         if (normalizers == null) {
85             normalizers = UNCOMMON_NORMALIZERS.getUnchecked(version);
86         }
87         normalizers.forEach(normalizer -> normalizer.apply(matchBuilder));
88
89         return matchBuilder.build();
90     }
91
92     private static @NonNull Stream<Function<MatchBuilder, MatchBuilder>> createNormalizers(final Uint8 version) {
93         return Stream.of(
94             MatchNormalizationUtil::normalizeExtensionMatch,
95             MatchNormalizationUtil::normalizeEthernetMatch,
96             MatchNormalizationUtil::normalizeArpMatch,
97             MatchNormalizationUtil::normalizeTunnelIpv4Match,
98             MatchNormalizationUtil::normalizeIpv4Match,
99             MatchNormalizationUtil::normalizeIpv4MatchArbitraryBitMask,
100             MatchNormalizationUtil::normalizeIpv6Match,
101             MatchNormalizationUtil::normalizeIpv6MatchArbitraryBitMask,
102             match -> normalizeInPortMatch(match, version),
103             match -> normalizeInPhyPortMatch(match, version));
104     }
105
106     private static @NonNull MatchBuilder normalizeExtensionMatch(@NonNull final MatchBuilder match) {
107         return new MatchBuilder(MatchUtil.transformMatch(match.build(), Match.class));
108     }
109
110     @VisibleForTesting
111     static @NonNull MatchBuilder normalizeInPortMatch(final @NonNull MatchBuilder match, final Uint8 version) {
112         final var inPort = match.getInPort();
113         if (inPort != null) {
114             final var inPortUri = normalizeProtocolAgnosticPort(inPort, version);
115             if (inPortUri != null) {
116                 match.setInPort(new NodeConnectorId(inPortUri));
117             }
118         }
119         return match;
120     }
121
122     @VisibleForTesting
123     static @NonNull MatchBuilder normalizeInPhyPortMatch(final @NonNull MatchBuilder match, final Uint8 version) {
124         final var inPhyPort = match.getInPhyPort();
125         if (inPhyPort != null) {
126             final var inPhyPortUri = normalizeProtocolAgnosticPort(inPhyPort, version);
127             if (inPhyPortUri != null) {
128                 match.setInPhyPort(new NodeConnectorId(inPhyPortUri));
129             }
130         }
131         return match;
132     }
133
134     @VisibleForTesting
135     static @NonNull MatchBuilder normalizeArpMatch(final @NonNull MatchBuilder match) {
136         if (match.getLayer3Match() instanceof ArpMatch arp) {
137             final var builder = new ArpMatchBuilder(arp)
138                 .setArpSourceTransportAddress(normalizeIpv4Prefix(arp.getArpSourceTransportAddress()))
139                 .setArpTargetTransportAddress(normalizeIpv4Prefix(arp.getArpTargetTransportAddress()));
140
141             final var arpSource = arp.getArpSourceHardwareAddress();
142             if (arpSource != null) {
143                 builder.setArpSourceHardwareAddress(new ArpSourceHardwareAddressBuilder(arpSource)
144                     .setAddress(normalizeMacAddress(arpSource.getAddress()))
145                     .setMask(normalizeMacAddress(arpSource.getMask()))
146                     .build());
147             }
148             final var arpTarget = arp.getArpTargetHardwareAddress();
149             if (arpTarget != null) {
150                 builder.setArpTargetHardwareAddress(new ArpTargetHardwareAddressBuilder(arpTarget)
151                     .setAddress(normalizeMacAddress(arpTarget.getAddress()))
152                     .setMask(normalizeMacAddress(arpTarget.getMask()))
153                     .build());
154             }
155             match.setLayer3Match(builder.build());
156         }
157         return match;
158     }
159
160     @VisibleForTesting
161     static @NonNull MatchBuilder normalizeTunnelIpv4Match(final @NonNull MatchBuilder match) {
162         if (match.getLayer3Match() instanceof TunnelIpv4Match tunnelIpv4) {
163             match.setLayer3Match(new TunnelIpv4MatchBuilder(tunnelIpv4)
164                 .setTunnelIpv4Source(normalizeIpv4Prefix(tunnelIpv4.getTunnelIpv4Source()))
165                 .setTunnelIpv4Destination(normalizeIpv4Prefix(tunnelIpv4.getTunnelIpv4Destination()))
166                 .build());
167         }
168         return match;
169     }
170
171     @VisibleForTesting
172     static @NonNull MatchBuilder normalizeIpv4Match(final @NonNull MatchBuilder match) {
173         if (match.getLayer3Match() instanceof Ipv4Match ipv4) {
174             match.setLayer3Match(new Ipv4MatchBuilder(ipv4)
175                 .setIpv4Source(normalizeIpv4Prefix(ipv4.getIpv4Source()))
176                 .setIpv4Destination(normalizeIpv4Prefix(ipv4.getIpv4Destination()))
177                 .build());
178         }
179         return match;
180     }
181
182     @NonNull
183     @VisibleForTesting
184     static MatchBuilder normalizeIpv4MatchArbitraryBitMask(final @NonNull MatchBuilder match) {
185         if (match.getLayer3Match() instanceof Ipv4MatchArbitraryBitMask ipv4arbitrary) {
186             match.setLayer3Match(new Ipv4MatchBuilder()
187                 .setIpv4Source(normalizeIpv4Arbitrary(
188                     ipv4arbitrary.getIpv4SourceAddressNoMask(),
189                     ipv4arbitrary.getIpv4SourceArbitraryBitmask()))
190                 .setIpv4Destination(normalizeIpv4Arbitrary(
191                     ipv4arbitrary.getIpv4DestinationAddressNoMask(),
192                     ipv4arbitrary.getIpv4DestinationArbitraryBitmask()))
193                 .build());
194         }
195         return match;
196     }
197
198     @VisibleForTesting
199     static @NonNull MatchBuilder normalizeIpv6Match(final @NonNull MatchBuilder match) {
200         if (match.getLayer3Match() instanceof Ipv6Match ipv6) {
201             match.setLayer3Match(new Ipv6MatchBuilder(ipv6)
202                 .setIpv6NdSll(normalizeMacAddress(ipv6.getIpv6NdSll()))
203                 .setIpv6NdTll(normalizeMacAddress(ipv6.getIpv6NdTll()))
204                 .setIpv6NdTarget(normalizeIpv6AddressWithoutMask(ipv6.getIpv6NdTarget()))
205                 .setIpv6Source(normalizeIpv6Prefix(ipv6.getIpv6Source()))
206                 .setIpv6Destination(normalizeIpv6Prefix(ipv6.getIpv6Destination()))
207                 .build());
208         }
209         return match;
210     }
211
212     @VisibleForTesting
213     static @NonNull MatchBuilder normalizeIpv6MatchArbitraryBitMask(final @NonNull MatchBuilder match) {
214         if (match.getLayer3Match() instanceof Ipv6MatchArbitraryBitMask ipv6Arbitrary) {
215             match.setLayer3Match(new Ipv6MatchBuilder()
216                 .setIpv6Source(normalizeIpv6Arbitrary(
217                     ipv6Arbitrary.getIpv6SourceAddressNoMask(),
218                     ipv6Arbitrary.getIpv6SourceArbitraryBitmask()))
219                 .setIpv6Destination(normalizeIpv6Arbitrary(
220                     ipv6Arbitrary.getIpv6DestinationAddressNoMask(),
221                     ipv6Arbitrary.getIpv6DestinationArbitraryBitmask()))
222                 .build());
223         }
224         return match;
225     }
226
227     @VisibleForTesting
228     static @NonNull MatchBuilder normalizeEthernetMatch(final @NonNull MatchBuilder match) {
229         final var eth = match.getEthernetMatch();
230         if (eth != null) {
231             final var builder = new EthernetMatchBuilder(eth);
232             final var source = eth.getEthernetSource();
233             if (source != null) {
234                 builder.setEthernetSource(new EthernetSourceBuilder(source)
235                     .setAddress(normalizeMacAddress(source.getAddress()))
236                     .setMask(normalizeMacAddressMask(source.getMask()))
237                     .build());
238             }
239             final var dest = eth.getEthernetDestination();
240             if (dest != null) {
241                 builder.setEthernetDestination(new EthernetDestinationBuilder(dest)
242                     .setAddress(normalizeMacAddress(dest.getAddress()))
243                     .setMask(normalizeMacAddressMask(dest.getMask()))
244                     .build());
245             }
246             match.setEthernetMatch(builder.build());
247         }
248         return match;
249     }
250 }