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