Optimize MaskUtil
[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 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
18 import org.apache.commons.lang3.exception.ExceptionUtils;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.SimpleAddress;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.Address;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.InstanceId;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv4;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv4Prefix;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv6;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.Ipv6Prefix;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.ServicePath;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.lisp.address.types.rev151105.lisp.address.address.SourceDestKey;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 public final class MaskUtil {
34     private static final Logger LOG = LoggerFactory.getLogger(MaskUtil.class);
35     private static final short IPV4_MAX_MASK = 32;
36     private static final short IPV6_MAX_MASK = 128;
37
38     // Utility class, should not be instantiated
39     private MaskUtil() {
40     }
41
42     public static boolean isMaskable(Address address) {
43         if (address instanceof Ipv4Prefix || address instanceof Ipv6Prefix || address instanceof SourceDestKey) {
44             return true;
45         } else if (address instanceof InstanceId) {
46             return isMaskable(((InstanceId)address).getInstanceId().getAddress());
47         }
48         return false;
49     }
50
51     public static boolean isMaskable(SimpleAddress address) {
52         if (address.getIpPrefix() != null) {
53             return true;
54         }
55         return false;
56     }
57
58     private static final int slashPosition(final String prefix) {
59         final int slash = prefix.lastIndexOf('/');
60         Preconditions.checkArgument(slash >= 0, "Argument %s does not contain a slash", prefix);
61         return slash;
62     }
63
64     private static String getPrefixAddress(final String prefix) {
65         return prefix.substring(0, slashPosition(prefix));
66     }
67
68     private static String getPrefixMask(final String prefix) {
69         return prefix.substring(slashPosition(prefix) + 1);
70     }
71
72     private static String[] splitPrefix(final String prefix) {
73         final int slash = slashPosition(prefix);
74         return new String[] { prefix.substring(0, slash), prefix.substring(slash + 1) };
75     }
76
77     public static Eid normalize(Eid eid, short mask) {
78         Address address = eid.getAddress();
79         try {
80             if (address instanceof Ipv4Prefix) {
81                 final String addr = getPrefixAddress(((Ipv4Prefix)address).getIpv4Prefix().getValue());
82                 InetAddress normalized = normalizeIP(InetAddresses.forString(addr), mask);
83                 return LispAddressUtil.asIpv4PrefixEid(eid, (Inet4Address)normalized, mask);
84             } else if (address instanceof Ipv6Prefix) {
85                 final String addr = getPrefixAddress(((Ipv6Prefix)address).getIpv6Prefix().getValue());
86                 InetAddress normalized = normalizeIP(InetAddresses.forString(addr), mask);
87                 return LispAddressUtil.asIpv6PrefixEid(eid, (Inet6Address)normalized, mask);
88             } else if (address instanceof InstanceId) {
89                 // TODO - not absolutely necessary, but should be implemented
90                 return eid;
91             }
92         } catch (UnknownHostException e) {
93             LOG.trace("Failed to normalize eid {} with mask {}: {}", eid, mask, ExceptionUtils.getStackTrace(e));
94         }
95         return eid;
96     }
97
98     public static Eid normalize(Eid eid) {
99         Address address = eid.getAddress();
100         try {
101             if (address instanceof Ipv4Prefix) {
102                 String[] v4prefix = splitPrefix(((Ipv4Prefix)address).getIpv4Prefix().getValue());
103                 short mask = Short.parseShort(v4prefix[1]);
104                 InetAddress normalized = normalizeIP(InetAddresses.forString(v4prefix[0]), mask);
105                 return LispAddressUtil.asIpv4PrefixEid(eid, (Inet4Address)normalized, mask);
106             } else if (address instanceof Ipv6Prefix) {
107                 String[] v6prefix = splitPrefix(((Ipv6Prefix)address).getIpv6Prefix().getValue());
108                 short mask = Short.parseShort(v6prefix[1]);
109                 InetAddress normalized = normalizeIP(InetAddresses.forString(v6prefix[0]), mask);
110                 return LispAddressUtil.asIpv6PrefixEid(eid, (Inet6Address)normalized, mask);
111             } else if (address instanceof Ipv4) {
112                 return LispAddressUtil.asIpv4PrefixEid(((Ipv4) address).getIpv4(), eid.getVirtualNetworkId());
113             } else if (address instanceof Ipv6) {
114                 return LispAddressUtil.asIpv6PrefixEid(((Ipv6) address).getIpv6(), eid.getVirtualNetworkId());
115             } else if (address instanceof InstanceId) {
116                 // TODO - not absolutely necessary, but should be implemented
117                 return eid;
118             } else if (address instanceof ServicePath) {
119                 // Build new Service Path eid with service index set to 0
120                 long spi = ((ServicePath) address).getServicePath().getServicePathId().getValue();
121                 long vni = eid.getVirtualNetworkId() != null ? eid.getVirtualNetworkId().getValue() : -1;
122                 return LispAddressUtil.asServicePathEid(vni, spi, (short)0);
123             }
124         } catch (UnknownHostException e) {
125             LOG.trace("Failed to normalize eid {}: {}", eid, ExceptionUtils.getStackTrace(e));
126         }
127         return eid;
128     }
129
130     private static InetAddress normalizeIP(InetAddress address, int maskLength) throws UnknownHostException {
131         ByteBuffer byteRepresentation = ByteBuffer.wrap(address.getAddress());
132         byte b = (byte) 0xff;
133         int mask = maskLength;
134         for (int i = 0; i < byteRepresentation.array().length; i++) {
135             if (mask >= 8) {
136                 byteRepresentation.put(i, (byte) (b & byteRepresentation.get(i)));
137             } else if (mask > 0) {
138                 byteRepresentation.put(i, (byte) ((byte) (b << (8 - mask)) & byteRepresentation.get(i)));
139             } else {
140                 byteRepresentation.put(i, (byte) (0 & byteRepresentation.get(i)));
141             }
142
143             mask -= 8;
144         }
145         return InetAddress.getByAddress(byteRepresentation.array());
146     }
147
148     public static int getMaxMask(Address address) {
149         if (address instanceof Ipv4 || address instanceof Ipv4Prefix) {
150             return IPV4_MAX_MASK;
151         } else if (address instanceof Ipv6 || address instanceof Ipv6Prefix) {
152             return IPV6_MAX_MASK;
153         } else {
154             return -1;
155         }
156     }
157
158     public static short getMaskForAddress(SimpleAddress address) {
159         if (address.getIpPrefix() == null) {
160             return -1;
161         }
162         return getMaskForIpPrefix(address.getIpPrefix());
163     }
164
165     private static String getIpPrefixString(IpPrefix prefix) {
166         if (prefix.getIpv4Prefix() != null) {
167             return prefix.getIpv4Prefix().getValue();
168         } else if (prefix.getIpv6Prefix() != null) {
169             return prefix.getIpv6Prefix().getValue();
170         } else {
171             throw new IllegalArgumentException("Invalid prefix " + prefix);
172         }
173     }
174
175     public static short getMaskForIpPrefix(IpPrefix prefix) {
176         return Short.parseShort(getPrefixMask(getIpPrefixString(prefix)));
177     }
178
179     public static String getAddressStringForIpPrefix(IpPrefix prefix) {
180         return getPrefixAddress(getIpPrefixString(prefix));
181     }
182
183     public static String getAddressStringForIpv4Prefix(Ipv4Prefix prefix) {
184         return getPrefixAddress(prefix.getIpv4Prefix().getValue());
185     }
186
187     public static String getAddressStringForIpv6Prefix(Ipv6Prefix prefix) {
188         return getPrefixAddress(prefix.getIpv6Prefix().getValue());
189     }
190
191     public static short getMaskForAddress(Address address) {
192         if (address instanceof Ipv4) {
193             return IPV4_MAX_MASK;
194         } else if (address instanceof Ipv6) {
195             return IPV6_MAX_MASK;
196         } else if (address instanceof Ipv4Prefix) {
197             return Short.parseShort(getPrefixMask(((Ipv4Prefix)address).getIpv4Prefix().getValue()));
198         } else if (address instanceof Ipv6Prefix) {
199             return Short.parseShort(getPrefixMask(((Ipv6Prefix)address).getIpv6Prefix().getValue()));
200         } else if (address instanceof InstanceId) {
201             return getMaskForAddress(((InstanceId)address).getInstanceId().getAddress());
202         }
203         return -1;
204     }
205 }