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