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