Bump upstreams
[lispflowmapping.git] / mappingservice / lisp-proto / src / main / java / org / opendaylight / lispflowmapping / lisp / util / MaskUtil.java
1 /*
2  * Copyright (c) 2014, 2017 Contextream, Inc. 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.lispflowmapping.lisp.util;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.net.InetAddresses;
12 import java.net.Inet4Address;
13 import java.net.Inet6Address;
14 import java.net.InetAddress;
15 import java.net.UnknownHostException;
16 import java.nio.ByteBuffer;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.SimpleAddress;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.Address;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.InstanceId;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv4;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv4Prefix;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv6;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv6Prefix;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.ServicePath;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.SourceDestKey;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.source.dest.key.SourceDestKeyBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv4Binary;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv4PrefixBinary;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv6Binary;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.binary.address.types.rev160504.augmented.lisp.address.address.Ipv6PrefixBinary;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
34 import org.opendaylight.yangtools.yang.common.Uint8;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 public final class MaskUtil {
39     private static final Logger LOG = LoggerFactory.getLogger(MaskUtil.class);
40     public static final short IPV4_MAX_MASK = 32;
41     public static final Uint8 IPV4_MAX_MASK_UINT = Uint8.valueOf(IPV4_MAX_MASK);
42     public static final short IPV6_MAX_MASK = 128;
43     public static final Uint8 IPV6_MAX_MASK_UINT = Uint8.valueOf(IPV6_MAX_MASK);
44
45     // Utility class, should not be instantiated
46     private MaskUtil() {
47     }
48
49     public static boolean isMaskable(Address address) {
50         if (address instanceof Ipv4Prefix || address instanceof Ipv6Prefix
51                 || address instanceof Ipv4PrefixBinary || address instanceof Ipv6PrefixBinary
52                 || address instanceof SourceDestKey) {
53             return true;
54         } else if (address instanceof InstanceId) {
55             return isMaskable(((InstanceId)address).getInstanceId().getAddress());
56         }
57         return false;
58     }
59
60     public static boolean isMaskable(SimpleAddress address) {
61         if (address.getIpPrefix() != null) {
62             return true;
63         }
64         return false;
65     }
66
67     private static int slashPosition(final String prefix) {
68         final int slash = prefix.lastIndexOf('/');
69         Preconditions.checkArgument(slash >= 0, "Argument %s does not contain a slash", prefix);
70         return slash;
71     }
72
73     public static String getPrefixAddress(final String prefix) {
74         return prefix.substring(0, slashPosition(prefix));
75     }
76
77     public static String getPrefixMask(final String prefix) {
78         return prefix.substring(slashPosition(prefix) + 1);
79     }
80
81     private static String[] splitPrefix(final String prefix) {
82         final int slash = slashPosition(prefix);
83         return new String[] { prefix.substring(0, slash), prefix.substring(slash + 1) };
84     }
85
86     public static Eid normalize(Eid eid, short mask) {
87         Address address = eid.getAddress();
88         try {
89             if (address instanceof Ipv4PrefixBinary) {
90                 byte[] addr = ((Ipv4PrefixBinary) address).getIpv4AddressBinary().getValue();
91                 return LispAddressUtil.asIpv4PrefixBinaryEid(eid, normalizeByteArray(addr, mask), mask);
92             } else if (address instanceof Ipv6PrefixBinary) {
93                 byte[] addr = ((Ipv6PrefixBinary) address).getIpv6AddressBinary().getValue();
94                 return LispAddressUtil.asIpv6PrefixBinaryEid(eid, normalizeByteArray(addr, mask), mask);
95             } else if (address instanceof Ipv4Prefix) {
96                 final String addr = getPrefixAddress(((Ipv4Prefix)address).getIpv4Prefix().getValue());
97                 InetAddress normalized = normalizeIP(InetAddresses.forString(addr), mask);
98                 return LispAddressUtil.asIpv4PrefixEid(eid, (Inet4Address)normalized, mask);
99             } else if (address instanceof Ipv6Prefix) {
100                 final String addr = getPrefixAddress(((Ipv6Prefix)address).getIpv6Prefix().getValue());
101                 InetAddress normalized = normalizeIP(InetAddresses.forString(addr), mask);
102                 return LispAddressUtil.asIpv6PrefixEid(eid, (Inet6Address)normalized, mask);
103             } else if (address instanceof InstanceId) {
104                 // TODO - not absolutely necessary, but should be implemented
105                 return eid;
106             }
107         } catch (UnknownHostException e) {
108             LOG.warn("Failed to normalize EID {} with mask {}, returning original EID", eid, mask, e);
109         }
110         return eid;
111     }
112
113     public static Eid normalize(Eid eid) {
114         Address address = eid.getAddress();
115         try {
116             if (address instanceof Ipv4PrefixBinary) {
117                 byte[] addr = ((Ipv4PrefixBinary) address).getIpv4AddressBinary().getValue();
118                 short mask = ((Ipv4PrefixBinary) address).getIpv4MaskLength().toJava();
119                 return LispAddressUtil.asIpv4PrefixBinaryEid(eid, normalizeByteArray(addr, mask), mask);
120             } else if (address instanceof Ipv6PrefixBinary) {
121                 byte[] addr = ((Ipv6PrefixBinary) address).getIpv6AddressBinary().getValue();
122                 short mask = ((Ipv6PrefixBinary) address).getIpv6MaskLength().toJava();
123                 return LispAddressUtil.asIpv6PrefixBinaryEid(eid, normalizeByteArray(addr, mask), mask);
124             } else if (address instanceof Ipv4Prefix) {
125                 String[] v4prefix = splitPrefix(((Ipv4Prefix)address).getIpv4Prefix().getValue());
126                 short mask = Short.parseShort(v4prefix[1]);
127                 InetAddress normalized = normalizeIP(InetAddresses.forString(v4prefix[0]), mask);
128                 return LispAddressUtil.asIpv4PrefixEid(eid, (Inet4Address) normalized, mask);
129             } else if (address instanceof Ipv6Prefix) {
130                 String[] v6prefix = splitPrefix(((Ipv6Prefix)address).getIpv6Prefix().getValue());
131                 short mask = Short.parseShort(v6prefix[1]);
132                 InetAddress normalized = normalizeIP(InetAddresses.forString(v6prefix[0]), mask);
133                 return LispAddressUtil.asIpv6PrefixEid(eid, (Inet6Address) normalized, mask);
134             } else if (address instanceof Ipv4) {
135                 return LispAddressUtil.asIpv4PrefixEid(((Ipv4) address).getIpv4(), eid.getVirtualNetworkId());
136             } else if (address instanceof Ipv6) {
137                 return LispAddressUtil.asIpv6PrefixEid(((Ipv6) address).getIpv6(), eid.getVirtualNetworkId());
138             } else if (address instanceof InstanceId) {
139                 // TODO - not absolutely necessary, but should be implemented
140                 return eid;
141             } else if (address instanceof SourceDestKey) {
142                 return normalizeSrcDst(eid);
143             } else if (address instanceof ServicePath) {
144                 // Build new Service Path eid with service index set to 0
145                 long spi = ((ServicePath) address).getServicePath().getServicePathId().getValue().toJava();
146                 long vni = eid.getVirtualNetworkId() != null ? eid.getVirtualNetworkId().getValue().toJava() : -1;
147                 return LispAddressUtil.asServicePathEid(vni, spi, (short)0);
148             }
149         } catch (UnknownHostException e) {
150             LOG.warn("Failed to normalize EID {}, returning original", eid, e);
151         }
152         return eid;
153     }
154
155     private static Eid normalizeSrcDst(Eid eid) throws UnknownHostException {
156         final SimpleAddress normalizedSrc = normalizeSimpleAddress(
157                 ((SourceDestKey) eid.getAddress()).getSourceDestKey().getSource());
158         final SimpleAddress normalizedDst = normalizeSimpleAddress(
159                 ((SourceDestKey) eid.getAddress()).getSourceDestKey().getDest());
160         return LispAddressUtil.asSrcDstEid(new SourceDestKeyBuilder()
161                 .setSource(normalizedSrc).setDest(normalizedDst).build(), eid.getVirtualNetworkId());
162     }
163
164     private static SimpleAddress normalizeSimpleAddress(SimpleAddress address) throws UnknownHostException {
165         if (address.getIpPrefix() == null) {
166             return address;
167         }
168         return new SimpleAddress(normalizeIpPrefix(address.getIpPrefix()));
169     }
170
171     private static IpPrefix normalizeIpPrefix(IpPrefix address) throws UnknownHostException {
172         String[] prefix = splitPrefix(address.stringValue());
173         short mask = Short.parseShort(prefix[1]);
174
175         InetAddress normalizedAddress = normalizeIP(InetAddresses.forString(prefix[0]), mask);
176         return IetfInetUtil.ipPrefixFor(normalizedAddress.getAddress(), mask);
177     }
178
179     private static InetAddress normalizeIP(InetAddress address, int maskLength) throws UnknownHostException {
180         return InetAddress.getByAddress(normalizeByteArray(address.getAddress(), (short) maskLength));
181     }
182
183     public static byte[] normalizeByteArray(byte[] address, short maskLength) {
184         ByteBuffer byteRepresentation = ByteBuffer.wrap(address);
185         byte byteMask = (byte) 0xff;
186         int mask = maskLength;
187         for (int i = 0; i < byteRepresentation.array().length; i++) {
188             if (mask >= 8) {
189                 byteRepresentation.put(i, (byte) (byteMask & byteRepresentation.get(i)));
190             } else if (mask > 0) {
191                 byteRepresentation.put(i, (byte) ((byte) (byteMask << 8 - mask) & byteRepresentation.get(i)));
192             } else {
193                 byteRepresentation.put(i, (byte) (0 & byteRepresentation.get(i)));
194             }
195
196             mask -= 8;
197         }
198         return byteRepresentation.array();
199     }
200
201     public static int getMaxMask(Address address) {
202         if (address instanceof Ipv4 || address instanceof Ipv4Prefix || address instanceof Ipv4Binary
203                 || address instanceof Ipv4PrefixBinary) {
204             return IPV4_MAX_MASK;
205         } else if (address instanceof Ipv6 || address instanceof Ipv6Prefix || address instanceof Ipv4Binary
206                 || address instanceof Ipv6PrefixBinary) {
207             return IPV6_MAX_MASK;
208         } else {
209             return -1;
210         }
211     }
212
213     private static String getIpPrefixString(IpPrefix prefix) {
214         if (prefix.getIpv4Prefix() != null) {
215             return prefix.getIpv4Prefix().getValue();
216         } else if (prefix.getIpv6Prefix() != null) {
217             return prefix.getIpv6Prefix().getValue();
218         } else {
219             throw new IllegalArgumentException("Invalid prefix " + prefix);
220         }
221     }
222
223     public static short getMaskForIpPrefix(IpPrefix prefix) {
224         return Short.parseShort(getPrefixMask(getIpPrefixString(prefix)));
225     }
226
227     public static String getAddressStringForIpPrefix(IpPrefix prefix) {
228         return getPrefixAddress(getIpPrefixString(prefix));
229     }
230
231     public static String getAddressStringForIpv4Prefix(Ipv4Prefix prefix) {
232         return getPrefixAddress(prefix.getIpv4Prefix().getValue());
233     }
234
235     public static String getAddressStringForIpv6Prefix(Ipv6Prefix prefix) {
236         return getPrefixAddress(prefix.getIpv6Prefix().getValue());
237     }
238
239     public static short getMaskForAddress(SimpleAddress address) {
240         if (address.getIpPrefix() == null) {
241             return -1;
242         }
243         return getMaskForIpPrefix(address.getIpPrefix());
244     }
245
246     public static short getMaskForAddress(Address address) {
247         if (address instanceof Ipv4) {
248             return IPV4_MAX_MASK;
249         } else if (address instanceof Ipv6) {
250             return IPV6_MAX_MASK;
251         } else if (address instanceof Ipv4Binary) {
252             return IPV4_MAX_MASK;
253         } else if (address instanceof Ipv6Binary) {
254             return IPV6_MAX_MASK;
255         } else if (address instanceof Ipv4Prefix) {
256             return Short.parseShort(getPrefixMask(((Ipv4Prefix) address).getIpv4Prefix().getValue()));
257         } else if (address instanceof Ipv6Prefix) {
258             return Short.parseShort(getPrefixMask(((Ipv6Prefix) address).getIpv6Prefix().getValue()));
259         } else if (address instanceof InstanceId) {
260             return getMaskForAddress(((InstanceId)address).getInstanceId().getAddress());
261         } else if (address instanceof Ipv4PrefixBinary) {
262             return ((Ipv4PrefixBinary) address).getIpv4MaskLength().toJava();
263         } else if (address instanceof Ipv6PrefixBinary) {
264             return ((Ipv6PrefixBinary) address).getIpv6MaskLength().toJava();
265         }
266         return -1;
267     }
268 }