blob: 0a6a5a3196d60c6ad461fc460d909e50448b9611 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
Thomas Vachuska24c849c2014-10-27 09:53:05 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Thomas Vachuska24c849c2014-10-27 09:53:05 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070015 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070016package org.onlab.packet;
17
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070018import java.util.Objects;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070019
20/**
Thomas Vachuska4b420772014-10-30 16:46:17 -070021 * A class representing an IP prefix. A prefix consists of an IP address and
22 * a subnet mask.
Pavlin Radoslavovf182f012014-11-04 15:03:18 -080023 * This class is immutable.
Thomas Vachuska4b420772014-10-30 16:46:17 -070024 * <p>
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070025 * NOTE: The stored IP address in the result IP prefix is masked to
26 * contain zeroes in all bits after the prefix length.
Thomas Vachuska4b420772014-10-30 16:46:17 -070027 * </p>
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070028 */
Pavlin Radoslavovf182f012014-11-04 15:03:18 -080029public class IpPrefix {
Charles Chan4ca8e602016-02-25 18:05:59 -080030 /**
31 * Longest IPv4 network prefix.
32 */
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070033 public static final int MAX_INET_MASK_LENGTH = IpAddress.INET_BIT_LENGTH;
Charles Chan4ca8e602016-02-25 18:05:59 -080034 /**
35 * Longest IPv6 network prefix.
36 */
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070037 public static final int MAX_INET6_MASK_LENGTH = IpAddress.INET6_BIT_LENGTH;
Charles Chan4ca8e602016-02-25 18:05:59 -080038 /**
39 * An IpPrefix that contains all IPv4 multicast addresses.
40 */
Charles Chanaedabfd2016-02-26 09:31:48 -080041 public static final IpPrefix IPV4_MULTICAST_PREFIX = IpPrefix.valueOf("224.0.0.0/4");
Charles Chan4ca8e602016-02-25 18:05:59 -080042 /**
43 * An IpPrefix that contains all IPv6 multicast addresses.
44 */
Charles Chanaedabfd2016-02-26 09:31:48 -080045 public static final IpPrefix IPV6_MULTICAST_PREFIX = IpPrefix.valueOf("ff00::/8");
Yi Tseng13a41a12017-07-26 13:45:01 -070046 /**
47 * An IpPrefix that contains all IPv4 link local addresses.
48 */
49 public static final IpPrefix IPV4_LINK_LOCAL_PREFIX = IpPrefix.valueOf("169.254.0.0/16");
50 /**
51 * An IpPrefix that contains all IPv6 link local addresses.
52 */
53 public static final IpPrefix IPV6_LINK_LOCAL_PREFIX = IpPrefix.valueOf("fe80::/64");
Jonathan Hart7f4bc522016-02-20 11:32:43 -080054
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070055 private final IpAddress address;
56 private final short prefixLength;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070057
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070058 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070059 * Constructor for given IP address, and a prefix length.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070060 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070061 * @param address the IP address
62 * @param prefixLength the prefix length
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070063 * @throws IllegalArgumentException if the prefix length value is invalid
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070064 */
Pavlin Radoslavovf182f012014-11-04 15:03:18 -080065 protected IpPrefix(IpAddress address, int prefixLength) {
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -080066 checkPrefixLength(address.version(), prefixLength);
67 this.address = IpAddress.makeMaskedAddress(address, prefixLength);
68 this.prefixLength = (short) prefixLength;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070069 }
70
71 /**
Pier Ventre48ca5192016-11-28 16:52:24 -080072 * Default constructor for Kryo serialization.
73 */
74 protected IpPrefix() {
75 this.address = null;
76 this.prefixLength = 0;
77 }
78
79 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070080 * Returns the IP version of the prefix.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070081 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070082 * @return the IP version of the prefix
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070083 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070084 public IpAddress.Version version() {
85 return address.version();
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070086 }
87
88 /**
Pavlin Radoslavov34ffe722015-03-10 12:48:55 -070089 * Tests whether the IP version of this prefix is IPv4.
90 *
91 * @return true if the IP version of this prefix is IPv4, otherwise false.
92 */
93 public boolean isIp4() {
94 return address.isIp4();
95 }
96
97 /**
98 * Tests whether the IP version of this prefix is IPv6.
99 *
100 * @return true if the IP version of this prefix is IPv6, otherwise false.
101 */
102 public boolean isIp6() {
103 return address.isIp6();
104 }
105
106 /**
Charles Chanaedabfd2016-02-26 09:31:48 -0800107 * Check if this IP prefix is a multicast prefix.
108 *
109 * @return true if this prefix a multicast prefix
110 */
111 public boolean isMulticast() {
112 return isIp4() ?
113 IPV4_MULTICAST_PREFIX.contains(this.getIp4Prefix()) :
114 IPV6_MULTICAST_PREFIX.contains(this.getIp6Prefix());
115 }
116
117 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700118 * Returns the IP address value of the prefix.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700119 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700120 * @return the IP address value of the prefix
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700121 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700122 public IpAddress address() {
123 return address;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700124 }
125
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700126 /**
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700127 * Returns the IP address prefix length.
128 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700129 * @return the IP address prefix length
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700130 */
131 public int prefixLength() {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700132 return prefixLength;
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700133 }
134
135 /**
Pavlin Radoslavov34c81642014-11-04 16:21:38 -0800136 * Gets the {@link Ip4Prefix} view of the IP prefix.
137 *
138 * @return the {@link Ip4Prefix} view of the IP prefix if it is IPv4,
139 * otherwise null
140 */
141 public Ip4Prefix getIp4Prefix() {
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700142 if (!isIp4()) {
Pavlin Radoslavov34c81642014-11-04 16:21:38 -0800143 return null;
144 }
145
146 // Return this object itself if it is already instance of Ip4Prefix
147 if (this instanceof Ip4Prefix) {
148 return (Ip4Prefix) this;
149 }
150 return Ip4Prefix.valueOf(address.getIp4Address(), prefixLength);
151 }
152
153 /**
154 * Gets the {@link Ip6Prefix} view of the IP prefix.
155 *
156 * @return the {@link Ip6Prefix} view of the IP prefix if it is IPv6,
157 * otherwise null
158 */
159 public Ip6Prefix getIp6Prefix() {
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700160 if (!isIp6()) {
Pavlin Radoslavov34c81642014-11-04 16:21:38 -0800161 return null;
162 }
163
164 // Return this object itself if it is already instance of Ip6Prefix
165 if (this instanceof Ip6Prefix) {
166 return (Ip6Prefix) this;
167 }
168 return Ip6Prefix.valueOf(address.getIp6Address(), prefixLength);
169 }
170
171 /**
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -0800172 * Converts an integer and a prefix length into an IPv4 prefix.
173 *
174 * @param address an integer representing the IPv4 address
175 * @param prefixLength the prefix length
176 * @return an IP prefix
177 * @throws IllegalArgumentException if the prefix length value is invalid
178 */
179 public static IpPrefix valueOf(int address, int prefixLength) {
180 return new IpPrefix(IpAddress.valueOf(address), prefixLength);
181 }
182
183 /**
184 * Converts a byte array and a prefix length into an IP prefix.
185 *
186 * @param version the IP address version
187 * @param address the IP address value stored in network byte order
188 * @param prefixLength the prefix length
189 * @return an IP prefix
190 * @throws IllegalArgumentException if the prefix length value is invalid
191 */
192 public static IpPrefix valueOf(IpAddress.Version version, byte[] address,
193 int prefixLength) {
194 return new IpPrefix(IpAddress.valueOf(version, address), prefixLength);
195 }
196
197 /**
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800198 * Converts an IP address and a prefix length into an IP prefix.
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -0800199 *
200 * @param address the IP address
201 * @param prefixLength the prefix length
202 * @return an IP prefix
203 * @throws IllegalArgumentException if the prefix length value is invalid
204 */
205 public static IpPrefix valueOf(IpAddress address, int prefixLength) {
206 return new IpPrefix(address, prefixLength);
207 }
208
209 /**
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800210 * Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16" or
211 * "1111:2222::/64") into an IP prefix.
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -0800212 *
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800213 * @param address an IP prefix in string form (e.g. "10.1.0.0/16" or
214 * "1111:2222::/64")
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -0800215 * @return an IP prefix
216 * @throws IllegalArgumentException if the arguments are invalid
217 */
218 public static IpPrefix valueOf(String address) {
219 final String[] parts = address.split("/");
220 if (parts.length != 2) {
Pavlin Radoslavovd7b45842015-03-20 15:40:59 -0700221 String msg = "Malformed IP prefix string: " + address + ". " +
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800222 "Address must take form \"x.x.x.x/y\" or " +
223 "\"xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/y\"";
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -0800224 throw new IllegalArgumentException(msg);
225 }
226 IpAddress ipAddress = IpAddress.valueOf(parts[0]);
227 int prefixLength = Integer.parseInt(parts[1]);
228
229 return new IpPrefix(ipAddress, prefixLength);
230 }
231
232 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700233 * Determines whether a given IP prefix is contained within this prefix.
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700234 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700235 * @param other the IP prefix to test
236 * @return true if the other IP prefix is contained in this prefix,
237 * otherwise false
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700238 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700239 public boolean contains(IpPrefix other) {
Pavlin Radoslavovdbeab4c2015-02-23 09:37:49 -0800240 if (version() != other.version()) {
241 return false;
242 }
243
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700244 if (this.prefixLength > other.prefixLength) {
245 return false; // This prefix has smaller prefix size
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700246 }
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700247
248 //
249 // Mask the other address with my prefix length.
250 // If the other prefix is within this prefix, the masked address must
251 // be same as the address of this prefix.
252 //
253 IpAddress maskedAddr =
254 IpAddress.makeMaskedAddress(other.address, this.prefixLength);
255 return this.address.equals(maskedAddr);
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700256 }
257
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700258 /**
259 * Determines whether a given IP address is contained within this prefix.
260 *
261 * @param other the IP address to test
262 * @return true if the IP address is contained in this prefix, otherwise
263 * false
264 */
265 public boolean contains(IpAddress other) {
Pavlin Radoslavovdbeab4c2015-02-23 09:37:49 -0800266 if (version() != other.version()) {
267 return false;
268 }
269
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700270 //
271 // Mask the other address with my prefix length.
272 // If the other prefix is within this prefix, the masked address must
273 // be same as the address of this prefix.
274 //
275 IpAddress maskedAddr =
276 IpAddress.makeMaskedAddress(other, this.prefixLength);
277 return this.address.equals(maskedAddr);
Jonathan Hart70da5122014-10-01 16:37:42 -0700278 }
279
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700280 @Override
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700281 public int hashCode() {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700282 return Objects.hash(address, prefixLength);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700283 }
284
285 @Override
286 public boolean equals(Object obj) {
287 if (this == obj) {
288 return true;
289 }
Pavlin Radoslavov50b70672014-11-05 11:22:25 -0800290 if ((obj == null) || (!(obj instanceof IpPrefix))) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700291 return false;
292 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700293 IpPrefix other = (IpPrefix) obj;
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700294 return ((prefixLength == other.prefixLength) &&
295 address.equals(other.address));
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700296 }
297
298 @Override
299 /*
300 * (non-Javadoc)
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700301 * The format is "x.x.x.x/y" for IPv4 prefixes.
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700302 *
303 * @see java.lang.Object#toString()
304 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700305 public String toString() {
306 final StringBuilder builder = new StringBuilder();
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700307 builder.append(address.toString());
308 builder.append("/");
309 builder.append(String.format("%d", prefixLength));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700310 return builder.toString();
311 }
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -0800312
313 /**
314 * Checks whether the prefix length is valid.
315 *
316 * @param version the IP address version
317 * @param prefixLength the prefix length value to check
318 * @throws IllegalArgumentException if the prefix length value is invalid
319 */
320 private static void checkPrefixLength(IpAddress.Version version,
321 int prefixLength) {
322 int maxPrefixLen = 0;
323
324 switch (version) {
325 case INET:
326 maxPrefixLen = MAX_INET_MASK_LENGTH;
327 break;
328 case INET6:
329 maxPrefixLen = MAX_INET6_MASK_LENGTH;
330 break;
331 default:
332 String msg = "Invalid IP version " + version;
333 throw new IllegalArgumentException(msg);
334 }
335
336 if ((prefixLength < 0) || (prefixLength > maxPrefixLen)) {
337 String msg = "Invalid prefix length " + prefixLength + ". " +
338 "The value must be in the interval [0, " +
339 maxPrefixLen + "]";
340 throw new IllegalArgumentException(msg);
341 }
342 }
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700343}