Merge "Use ClassToInstanceMap instead of a HashMap"
[openflowplugin.git] / openflowplugin-impl / src / main / java / org / opendaylight / openflowplugin / impl / util / AddressNormalizationUtil.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 java.net.InetAddress;
11 import java.net.UnknownHostException;
12 import java.util.Locale;
13 import javax.annotation.Nullable;
14 import org.opendaylight.openflowplugin.api.openflow.md.util.OpenflowVersion;
15 import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.common.IpConversionUtil;
16 import org.opendaylight.openflowplugin.openflow.md.util.InventoryDataServiceUtil;
17 import org.opendaylight.openflowplugin.openflow.md.util.OpenflowPortsUtil;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.opendaylight.ipv6.arbitrary.bitmask.fields.rev160224.Ipv6ArbitraryMask;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * Utility class used for converting OpenFlow port numbers, Ipv4 and Ipv6 addresses to normalized format.
32  */
33 public final class AddressNormalizationUtil {
34     private static final Logger LOG = LoggerFactory.getLogger(AddressNormalizationUtil.class);
35
36     private static final String NO_ETH_MASK = "ff:ff:ff:ff:ff:ff";
37     private static final String PREFIX_SEPARATOR = "/";
38
39     private AddressNormalizationUtil() {
40     }
41
42     /**
43      * Extract port number from URI and convert it to OpenFlow specific textual representation.
44      *
45      * @param port            the OpenFlow port
46      * @param protocolVersion the OpenFLow protocol version
47      * @return normalized uri
48      */
49     @Nullable
50     public static Uri normalizeProtocolAgnosticPort(@Nullable final Uri port, final short protocolVersion) {
51         if (port == null) {
52             return null;
53         }
54
55         Long portValue = InventoryDataServiceUtil
56                 .portNumberfromNodeConnectorId(OpenflowVersion.get(protocolVersion), port.getValue());
57
58         return portValue == null ? null : OpenflowPortsUtil.getProtocolAgnosticPortUri(protocolVersion, portValue);
59     }
60
61     /**
62      * Normalize Ipv6 address with prefix mask (ex. 1234:5678:9ABC::/76) and apply prefix mask to Ipv6 address.
63      *
64      * @param ipv6Prefix the Ipv6 prefix
65      * @return normalized Ipv6 prefix
66      */
67     @Nullable
68     public static Ipv6Prefix normalizeIpv6Prefix(@Nullable final Ipv6Prefix ipv6Prefix) {
69         if (ipv6Prefix == null) {
70             return null;
71         }
72
73         final byte[] address = IetfInetUtil.INSTANCE.ipv6AddressBytes(IpConversionUtil.extractIpv6Address(ipv6Prefix));
74         final byte[] mask =
75                 IpConversionUtil.convertIpv6PrefixToByteArray(IpConversionUtil.extractIpv6Prefix(ipv6Prefix));
76         return normalizeIpv6Address(address, mask);
77     }
78
79     /**
80      * Normalize Ipv6 address and arbitrary mask and apply arbitrary mask to Ipv6 address.
81      *
82      * @param ipv6Address the Ipv4 address
83      * @param ipv4Mask    the Ipv4 mask
84      * @return normalized Ipv6 prefix
85      */
86     @Nullable
87     public static Ipv6Prefix normalizeIpv6Arbitrary(@Nullable final Ipv6Address ipv6Address,
88                                                     @Nullable final Ipv6ArbitraryMask ipv4Mask) {
89         if (ipv6Address == null) {
90             return null;
91         }
92
93         final byte[] address = IetfInetUtil.INSTANCE.ipv6AddressBytes(ipv6Address);
94         final byte[] mask = IpConversionUtil.convertIpv6ArbitraryMaskToByteArray(ipv4Mask);
95         return normalizeIpv6Address(address, mask);
96     }
97
98     /**
99      * Normalize ipv 6 address without mask.
100      *
101      * @param ipv6Address the Ipv6 address
102      * @return normalized Ipv6 address
103      */
104     @Nullable
105     public static Ipv6Address normalizeIpv6AddressWithoutMask(@Nullable final Ipv6Address ipv6Address) {
106         final Ipv6Prefix ipv6Prefix = normalizeIpv6Arbitrary(ipv6Address, null);
107         return ipv6Prefix == null ? null : new Ipv6Address(ipv6Prefix.getValue().split(PREFIX_SEPARATOR)[0]);
108     }
109
110     /**
111      * Normalize Ipv4 address with prefix mask (ex. 192.168.0.1/24) and apply prefix mask to Ipv4 address.
112      *
113      * @param ipv4Prefix the Ipv4 prefix
114      * @return normalized Ipv4 prefix
115      */
116     @Nullable
117     public static Ipv4Prefix normalizeIpv4Prefix(@Nullable final Ipv4Prefix ipv4Prefix) {
118         if (ipv4Prefix == null) {
119             return null;
120         }
121
122         final byte[] address = IetfInetUtil.INSTANCE.ipv4AddressBytes(IpConversionUtil.extractIpv4Address(ipv4Prefix));
123         final byte[] mask =
124                 IpConversionUtil.convertArbitraryMaskToByteArray(IpConversionUtil.extractIpv4AddressMask(ipv4Prefix));
125         return normalizeIpv4Address(address, mask);
126     }
127
128     /**
129      * Normalize Ipv4 address and arbitrary mask and apply arbitrary mask to Ipv4 address.
130      *
131      * @param ipv4Address the Ipv4 address
132      * @param ipv4Mask    the Ipv4 mask
133      * @return normalized Ipv4 prefix
134      */
135     @Nullable
136     public static Ipv4Prefix normalizeIpv4Arbitrary(@Nullable final Ipv4Address ipv4Address,
137                                                     @Nullable final DottedQuad ipv4Mask) {
138         if (ipv4Address == null) {
139             return null;
140         }
141
142         final byte[] address = IetfInetUtil.INSTANCE.ipv4AddressBytes(ipv4Address);
143         final byte[] mask = IpConversionUtil.convertArbitraryMaskToByteArray(ipv4Mask);
144         return normalizeIpv4Address(address, mask);
145     }
146
147     /**
148      * Normalize Ipv4 address and arbitrary mask in byte array format and apply arbitrary mask to Ipv4 address.
149      *
150      * @param address Ipv4 address byte array
151      * @param mask    Ipv4 mask byte array
152      * @return normalized Ipv4 prefix
153      */
154     @Nullable
155     public static Ipv4Prefix normalizeIpv4Address(@Nullable final byte[] address, @Nullable final byte[] mask) {
156         final String addressPrefix = normalizeInetAddressWithMask(normalizeIpAddress(address, mask), mask);
157
158         if (addressPrefix == null) {
159             return null;
160         }
161
162         return new Ipv4Prefix(addressPrefix);
163     }
164
165
166     /**
167      * Normalize Ipv6 address and arbitrary mask in byte array format and apply arbitrary mask to Ipv6 address.
168      *
169      * @param address Ipv6 address byte array
170      * @param mask    Ipv6 mask byte array
171      * @return normalized Ipv6 prefix
172      */
173     @Nullable
174     public static Ipv6Prefix normalizeIpv6Address(@Nullable final byte[] address, @Nullable final byte[] mask) {
175         final String addressPrefix = normalizeInetAddressWithMask(normalizeIpAddress(address, mask), mask);
176
177         if (addressPrefix == null) {
178             return null;
179         }
180
181         return new Ipv6Prefix(addressPrefix);
182     }
183
184     /**
185      * Normalize generic IP address and arbitrary mask in byte array format and apply arbitrary mask to IP address.
186      *
187      * @param address address byte array
188      * @param mask    mask byte array
189      * @return normalized Inet address
190      */
191     @Nullable
192     public static InetAddress normalizeIpAddress(@Nullable final byte[] address, @Nullable final byte[] mask) {
193         if (address == null) {
194             return null;
195         }
196
197         final byte[] result = new byte[address.length];
198
199         for (int i = 0; i < address.length; i++) {
200             result[i] = mask != null ? (byte) (address[i] & mask[i]) : address[i];
201         }
202
203         try {
204             return InetAddress.getByAddress(result);
205         } catch (UnknownHostException e) {
206             LOG.warn("Failed to recognize the host while normalizing IP address from bytes ", e);
207             return null;
208         }
209     }
210
211     /**
212      * Convert arbitrary mask to prefix mask and append it to textual representation of Inet address.
213      *
214      * @param address the address
215      * @param mask    the mask
216      * @return the string
217      */
218     @Nullable
219     public static String normalizeInetAddressWithMask(@Nullable final InetAddress address,
220                                                       @Nullable final byte[] mask) {
221         if (address == null) {
222             return null;
223         }
224
225         return address.getHostAddress()
226                 + (mask == null ? "" : PREFIX_SEPARATOR + String.valueOf(IpConversionUtil.countBits(mask)));
227     }
228
229     /**
230      * Convert MAC address to it's lower case format.
231      *
232      * @param macAddress the MAC address
233      * @return normalized MAC address
234      */
235     @Nullable
236     public static MacAddress normalizeMacAddress(@Nullable final MacAddress macAddress) {
237         return macAddress == null ? null : new MacAddress(macAddress.getValue().toLowerCase(Locale.ROOT));
238     }
239
240     /**
241      * Convert MAC address mask to it's lower case format and if it is full F mask, return null.
242      *
243      * @param macAddress the MAC address
244      * @return normalized MAC address
245      */
246     @Nullable
247     public static MacAddress normalizeMacAddressMask(@Nullable final MacAddress macAddress) {
248         final MacAddress normalizedMacAddress = normalizeMacAddress(macAddress);
249
250         if (normalizedMacAddress == null) {
251             return null;
252         }
253
254         if (NO_ETH_MASK.equals(normalizedMacAddress.getValue())) {
255             return null;
256         }
257
258         return normalizedMacAddress;
259     }
260 }