Use ByteBuf.readRetainedSlice()
[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  * Copyright (c) 2024 PANTHEON.tech, s.r.o.
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7  * and is available at http://www.eclipse.org/legal/epl-v10.html
8  */
9 package org.opendaylight.openflowplugin.impl.util;
10
11 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeIpv4Arbitrary;
12 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeIpv4Prefix;
13 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeIpv6AddressWithoutMask;
14 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeIpv6Arbitrary;
15 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeIpv6Prefix;
16 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeMacAddress;
17 import static org.opendaylight.openflowplugin.impl.util.AddressNormalizationUtil.normalizeMacAddressMask;
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 org.eclipse.jdt.annotation.NonNull;
24 import org.opendaylight.openflowplugin.api.OFConstants;
25 import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpSourceHardwareAddressBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpTargetHardwareAddressBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetSourceBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatch;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4Match;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchArbitraryBitMask;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6Match;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchArbitraryBitMask;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.TunnelIpv4Match;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.TunnelIpv4MatchBuilder;
44 import org.opendaylight.yangtools.yang.common.Uint8;
45
46 /**
47  * Utility class for match normalization.
48  */
49 // FIXME: rename to MatchNormalizer, move to FlowRegistryKeyFactory's package and hide
50 public final class MatchNormalizationUtil {
51     public static final @NonNull MatchNormalizationUtil VERSION_1_0 =
52         new MatchNormalizationUtil(OFConstants.OFP_VERSION_1_0);
53     public static final @NonNull MatchNormalizationUtil VERSION_1_3 =
54         new MatchNormalizationUtil(OFConstants.OFP_VERSION_1_3);
55     private static final LoadingCache<Uint8, @NonNull MatchNormalizationUtil> CACHE = CacheBuilder.newBuilder()
56         .weakValues().build(new CacheLoader<>() {
57             @Override
58             public MatchNormalizationUtil load(final Uint8 key) {
59                 return new MatchNormalizationUtil(key);
60             }
61         });
62
63     private final AddressNormalizationUtil addressNormalizer;
64
65     private MatchNormalizationUtil(final Uint8 version) {
66         addressNormalizer = AddressNormalizationUtil.ofVersion(OpenflowVersion.ofVersion(version));
67     }
68
69     public static @NonNull MatchNormalizationUtil ofVersion(final Uint8 version) {
70         if (OFConstants.OFP_VERSION_1_3.equals(version)) {
71             return VERSION_1_3;
72         } else if (OFConstants.OFP_VERSION_1_0.equals(version)) {
73             return VERSION_1_0;
74         } else {
75             return CACHE.getUnchecked(version);
76         }
77     }
78
79     /**
80      * Normalize match.
81      *
82      * @param match   the OpenFlow match
83      * @return normalized OpenFlow match
84      */
85     public @NonNull Match normalizeMatch(@NonNull final Match match) {
86         var builder = new MatchBuilder(match);
87         builder = normalizeExtensionMatch(builder);
88         builder = normalizeEthernetMatch(builder);
89         builder = normalizeArpMatch(builder);
90         builder = normalizeTunnelIpv4Match(builder);
91         builder = normalizeIpv4Match(builder);
92         builder = normalizeIpv4MatchArbitraryBitMask(builder);
93         builder = normalizeIpv6Match(builder);
94         builder = normalizeIpv6MatchArbitraryBitMask(builder);
95         builder = normalizeInPortMatch(builder);
96         builder = normalizeInPhyPortMatch(builder);
97         return builder.build();
98     }
99
100     @VisibleForTesting
101     @NonNull MatchBuilder normalizeInPortMatch(final @NonNull MatchBuilder match) {
102         final var inPort = match.getInPort();
103         if (inPort != null) {
104             final var inPortUri = addressNormalizer.normalizeProtocolAgnosticPort(inPort);
105             if (inPortUri != null) {
106                 match.setInPort(new NodeConnectorId(inPortUri));
107             }
108         }
109         return match;
110     }
111
112     @VisibleForTesting
113     @NonNull MatchBuilder normalizeInPhyPortMatch(final @NonNull MatchBuilder match) {
114         final var inPhyPort = match.getInPhyPort();
115         if (inPhyPort != null) {
116             final var inPhyPortUri = addressNormalizer.normalizeProtocolAgnosticPort(inPhyPort);
117             if (inPhyPortUri != null) {
118                 match.setInPhyPort(new NodeConnectorId(inPhyPortUri));
119             }
120         }
121         return match;
122     }
123
124     @VisibleForTesting
125     static @NonNull MatchBuilder normalizeArpMatch(final @NonNull MatchBuilder match) {
126         if (match.getLayer3Match() instanceof ArpMatch arp) {
127             final var builder = new ArpMatchBuilder(arp)
128                 .setArpSourceTransportAddress(normalizeIpv4Prefix(arp.getArpSourceTransportAddress()))
129                 .setArpTargetTransportAddress(normalizeIpv4Prefix(arp.getArpTargetTransportAddress()));
130
131             final var arpSource = arp.getArpSourceHardwareAddress();
132             if (arpSource != null) {
133                 builder.setArpSourceHardwareAddress(new ArpSourceHardwareAddressBuilder(arpSource)
134                     .setAddress(normalizeMacAddress(arpSource.getAddress()))
135                     .setMask(normalizeMacAddress(arpSource.getMask()))
136                     .build());
137             }
138             final var arpTarget = arp.getArpTargetHardwareAddress();
139             if (arpTarget != null) {
140                 builder.setArpTargetHardwareAddress(new ArpTargetHardwareAddressBuilder(arpTarget)
141                     .setAddress(normalizeMacAddress(arpTarget.getAddress()))
142                     .setMask(normalizeMacAddress(arpTarget.getMask()))
143                     .build());
144             }
145             match.setLayer3Match(builder.build());
146         }
147         return match;
148     }
149
150     @VisibleForTesting
151     static @NonNull MatchBuilder normalizeTunnelIpv4Match(final @NonNull MatchBuilder match) {
152         if (match.getLayer3Match() instanceof TunnelIpv4Match tunnelIpv4) {
153             match.setLayer3Match(new TunnelIpv4MatchBuilder(tunnelIpv4)
154                 .setTunnelIpv4Source(normalizeIpv4Prefix(tunnelIpv4.getTunnelIpv4Source()))
155                 .setTunnelIpv4Destination(normalizeIpv4Prefix(tunnelIpv4.getTunnelIpv4Destination()))
156                 .build());
157         }
158         return match;
159     }
160
161     @VisibleForTesting
162     static @NonNull MatchBuilder normalizeIpv4Match(final @NonNull MatchBuilder match) {
163         if (match.getLayer3Match() instanceof Ipv4Match ipv4) {
164             match.setLayer3Match(new Ipv4MatchBuilder(ipv4)
165                 .setIpv4Source(normalizeIpv4Prefix(ipv4.getIpv4Source()))
166                 .setIpv4Destination(normalizeIpv4Prefix(ipv4.getIpv4Destination()))
167                 .build());
168         }
169         return match;
170     }
171
172     @NonNull
173     @VisibleForTesting
174     static MatchBuilder normalizeIpv4MatchArbitraryBitMask(final @NonNull MatchBuilder match) {
175         if (match.getLayer3Match() instanceof Ipv4MatchArbitraryBitMask ipv4arbitrary) {
176             match.setLayer3Match(new Ipv4MatchBuilder()
177                 .setIpv4Source(normalizeIpv4Arbitrary(
178                     ipv4arbitrary.getIpv4SourceAddressNoMask(),
179                     ipv4arbitrary.getIpv4SourceArbitraryBitmask()))
180                 .setIpv4Destination(normalizeIpv4Arbitrary(
181                     ipv4arbitrary.getIpv4DestinationAddressNoMask(),
182                     ipv4arbitrary.getIpv4DestinationArbitraryBitmask()))
183                 .build());
184         }
185         return match;
186     }
187
188     @VisibleForTesting
189     static @NonNull MatchBuilder normalizeIpv6Match(final @NonNull MatchBuilder match) {
190         if (match.getLayer3Match() instanceof Ipv6Match ipv6) {
191             match.setLayer3Match(new Ipv6MatchBuilder(ipv6)
192                 .setIpv6NdSll(normalizeMacAddress(ipv6.getIpv6NdSll()))
193                 .setIpv6NdTll(normalizeMacAddress(ipv6.getIpv6NdTll()))
194                 .setIpv6NdTarget(normalizeIpv6AddressWithoutMask(ipv6.getIpv6NdTarget()))
195                 .setIpv6Source(normalizeIpv6Prefix(ipv6.getIpv6Source()))
196                 .setIpv6Destination(normalizeIpv6Prefix(ipv6.getIpv6Destination()))
197                 .build());
198         }
199         return match;
200     }
201
202     @VisibleForTesting
203     static @NonNull MatchBuilder normalizeIpv6MatchArbitraryBitMask(final @NonNull MatchBuilder match) {
204         if (match.getLayer3Match() instanceof Ipv6MatchArbitraryBitMask ipv6Arbitrary) {
205             match.setLayer3Match(new Ipv6MatchBuilder()
206                 .setIpv6Source(normalizeIpv6Arbitrary(
207                     ipv6Arbitrary.getIpv6SourceAddressNoMask(),
208                     ipv6Arbitrary.getIpv6SourceArbitraryBitmask()))
209                 .setIpv6Destination(normalizeIpv6Arbitrary(
210                     ipv6Arbitrary.getIpv6DestinationAddressNoMask(),
211                     ipv6Arbitrary.getIpv6DestinationArbitraryBitmask()))
212                 .build());
213         }
214         return match;
215     }
216
217     @VisibleForTesting
218     static @NonNull MatchBuilder normalizeEthernetMatch(final @NonNull MatchBuilder match) {
219         final var eth = match.getEthernetMatch();
220         if (eth != null) {
221             final var builder = new EthernetMatchBuilder(eth);
222             final var source = eth.getEthernetSource();
223             if (source != null) {
224                 builder.setEthernetSource(new EthernetSourceBuilder(source)
225                     .setAddress(normalizeMacAddress(source.getAddress()))
226                     .setMask(normalizeMacAddressMask(source.getMask()))
227                     .build());
228             }
229             final var dest = eth.getEthernetDestination();
230             if (dest != null) {
231                 builder.setEthernetDestination(new EthernetDestinationBuilder(dest)
232                     .setAddress(normalizeMacAddress(dest.getAddress()))
233                     .setMask(normalizeMacAddressMask(dest.getMask()))
234                     .build());
235             }
236             match.setEthernetMatch(builder.build());
237         }
238         return match;
239     }
240
241     private static @NonNull MatchBuilder normalizeExtensionMatch(@NonNull final MatchBuilder match) {
242         return new MatchBuilder(MatchUtil.transformMatch(match.build(), Match.class));
243     }
244 }