blob: 07539afc0fb578642de6db22201df66d333ab8fc [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
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 */
41 @Deprecated
Jonathan Hart7f4bc522016-02-20 11:32:43 -080042 public static final IpPrefix MULTICAST_RANGE = IpPrefix.valueOf("224.0.0.0/4");
Charles Chan4ca8e602016-02-25 18:05:59 -080043 /**
44 * An IpPrefix that contains all IPv4 multicast addresses.
45 */
Charles Chanaedabfd2016-02-26 09:31:48 -080046 public static final IpPrefix IPV4_MULTICAST_PREFIX = IpPrefix.valueOf("224.0.0.0/4");
Charles Chan4ca8e602016-02-25 18:05:59 -080047 /**
48 * An IpPrefix that contains all IPv6 multicast addresses.
49 */
Charles Chanaedabfd2016-02-26 09:31:48 -080050 public static final IpPrefix IPV6_MULTICAST_PREFIX = IpPrefix.valueOf("ff00::/8");
Yi Tseng13a41a12017-07-26 13:45:01 -070051 /**
52 * An IpPrefix that contains all IPv4 link local addresses.
53 */
54 public static final IpPrefix IPV4_LINK_LOCAL_PREFIX = IpPrefix.valueOf("169.254.0.0/16");
55 /**
56 * An IpPrefix that contains all IPv6 link local addresses.
57 */
58 public static final IpPrefix IPV6_LINK_LOCAL_PREFIX = IpPrefix.valueOf("fe80::/64");
Jonathan Hart7f4bc522016-02-20 11:32:43 -080059
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070060 private final IpAddress address;
61 private final short prefixLength;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070062
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070063 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070064 * Constructor for given IP address, and a prefix length.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070065 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070066 * @param address the IP address
67 * @param prefixLength the prefix length
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070068 * @throws IllegalArgumentException if the prefix length value is invalid
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070069 */
Pavlin Radoslavovf182f012014-11-04 15:03:18 -080070 protected IpPrefix(IpAddress address, int prefixLength) {
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -080071 checkPrefixLength(address.version(), prefixLength);
72 this.address = IpAddress.makeMaskedAddress(address, prefixLength);
73 this.prefixLength = (short) prefixLength;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070074 }
75
76 /**
Pier Ventre48ca5192016-11-28 16:52:24 -080077 * Default constructor for Kryo serialization.
78 */
79 protected IpPrefix() {
80 this.address = null;
81 this.prefixLength = 0;
82 }
83
84 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070085 * Returns the IP version of the prefix.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070086 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070087 * @return the IP version of the prefix
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070088 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070089 public IpAddress.Version version() {
90 return address.version();
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070091 }
92
93 /**
Pavlin Radoslavov34ffe722015-03-10 12:48:55 -070094 * Tests whether the IP version of this prefix is IPv4.
95 *
96 * @return true if the IP version of this prefix is IPv4, otherwise false.
97 */
98 public boolean isIp4() {
99 return address.isIp4();
100 }
101
102 /**
103 * Tests whether the IP version of this prefix is IPv6.
104 *
105 * @return true if the IP version of this prefix is IPv6, otherwise false.
106 */
107 public boolean isIp6() {
108 return address.isIp6();
109 }
110
111 /**
Charles Chanaedabfd2016-02-26 09:31:48 -0800112 * Check if this IP prefix is a multicast prefix.
113 *
114 * @return true if this prefix a multicast prefix
115 */
116 public boolean isMulticast() {
117 return isIp4() ?
118 IPV4_MULTICAST_PREFIX.contains(this.getIp4Prefix()) :
119 IPV6_MULTICAST_PREFIX.contains(this.getIp6Prefix());
120 }
121
122 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700123 * Returns the IP address value of the prefix.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700124 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700125 * @return the IP address value of the prefix
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700126 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700127 public IpAddress address() {
128 return address;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700129 }
130
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700131 /**
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700132 * Returns the IP address prefix length.
133 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700134 * @return the IP address prefix length
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700135 */
136 public int prefixLength() {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700137 return prefixLength;
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700138 }
139
140 /**
Pavlin Radoslavov34c81642014-11-04 16:21:38 -0800141 * Gets the {@link Ip4Prefix} view of the IP prefix.
142 *
143 * @return the {@link Ip4Prefix} view of the IP prefix if it is IPv4,
144 * otherwise null
145 */
146 public Ip4Prefix getIp4Prefix() {
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700147 if (!isIp4()) {
Pavlin Radoslavov34c81642014-11-04 16:21:38 -0800148 return null;
149 }
150
151 // Return this object itself if it is already instance of Ip4Prefix
152 if (this instanceof Ip4Prefix) {
153 return (Ip4Prefix) this;
154 }
155 return Ip4Prefix.valueOf(address.getIp4Address(), prefixLength);
156 }
157
158 /**
159 * Gets the {@link Ip6Prefix} view of the IP prefix.
160 *
161 * @return the {@link Ip6Prefix} view of the IP prefix if it is IPv6,
162 * otherwise null
163 */
164 public Ip6Prefix getIp6Prefix() {
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700165 if (!isIp6()) {
Pavlin Radoslavov34c81642014-11-04 16:21:38 -0800166 return null;
167 }
168
169 // Return this object itself if it is already instance of Ip6Prefix
170 if (this instanceof Ip6Prefix) {
171 return (Ip6Prefix) this;
172 }
173 return Ip6Prefix.valueOf(address.getIp6Address(), prefixLength);
174 }
175
176 /**
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -0800177 * Converts an integer and a prefix length into an IPv4 prefix.
178 *
179 * @param address an integer representing the IPv4 address
180 * @param prefixLength the prefix length
181 * @return an IP prefix
182 * @throws IllegalArgumentException if the prefix length value is invalid
183 */
184 public static IpPrefix valueOf(int address, int prefixLength) {
185 return new IpPrefix(IpAddress.valueOf(address), prefixLength);
186 }
187
188 /**
189 * Converts a byte array and a prefix length into an IP prefix.
190 *
191 * @param version the IP address version
192 * @param address the IP address value stored in network byte order
193 * @param prefixLength the prefix length
194 * @return an IP prefix
195 * @throws IllegalArgumentException if the prefix length value is invalid
196 */
197 public static IpPrefix valueOf(IpAddress.Version version, byte[] address,
198 int prefixLength) {
199 return new IpPrefix(IpAddress.valueOf(version, address), prefixLength);
200 }
201
202 /**
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800203 * Converts an IP address and a prefix length into an IP prefix.
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -0800204 *
205 * @param address the IP address
206 * @param prefixLength the prefix length
207 * @return an IP prefix
208 * @throws IllegalArgumentException if the prefix length value is invalid
209 */
210 public static IpPrefix valueOf(IpAddress address, int prefixLength) {
211 return new IpPrefix(address, prefixLength);
212 }
213
214 /**
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800215 * Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16" or
216 * "1111:2222::/64") into an IP prefix.
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -0800217 *
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800218 * @param address an IP prefix in string form (e.g. "10.1.0.0/16" or
219 * "1111:2222::/64")
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -0800220 * @return an IP prefix
221 * @throws IllegalArgumentException if the arguments are invalid
222 */
223 public static IpPrefix valueOf(String address) {
224 final String[] parts = address.split("/");
225 if (parts.length != 2) {
Pavlin Radoslavovd7b45842015-03-20 15:40:59 -0700226 String msg = "Malformed IP prefix string: " + address + ". " +
Pavlin Radoslavovf182f012014-11-04 15:03:18 -0800227 "Address must take form \"x.x.x.x/y\" or " +
228 "\"xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/y\"";
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -0800229 throw new IllegalArgumentException(msg);
230 }
231 IpAddress ipAddress = IpAddress.valueOf(parts[0]);
232 int prefixLength = Integer.parseInt(parts[1]);
233
234 return new IpPrefix(ipAddress, prefixLength);
235 }
236
237 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700238 * Determines whether a given IP prefix is contained within this prefix.
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700239 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700240 * @param other the IP prefix to test
241 * @return true if the other IP prefix is contained in this prefix,
242 * otherwise false
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700243 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700244 public boolean contains(IpPrefix other) {
Pavlin Radoslavovdbeab4c2015-02-23 09:37:49 -0800245 if (version() != other.version()) {
246 return false;
247 }
248
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700249 if (this.prefixLength > other.prefixLength) {
250 return false; // This prefix has smaller prefix size
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700251 }
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700252
253 //
254 // Mask the other address with my prefix length.
255 // If the other prefix is within this prefix, the masked address must
256 // be same as the address of this prefix.
257 //
258 IpAddress maskedAddr =
259 IpAddress.makeMaskedAddress(other.address, this.prefixLength);
260 return this.address.equals(maskedAddr);
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700261 }
262
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700263 /**
264 * Determines whether a given IP address is contained within this prefix.
265 *
266 * @param other the IP address to test
267 * @return true if the IP address is contained in this prefix, otherwise
268 * false
269 */
270 public boolean contains(IpAddress other) {
Pavlin Radoslavovdbeab4c2015-02-23 09:37:49 -0800271 if (version() != other.version()) {
272 return false;
273 }
274
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700275 //
276 // Mask the other address with my prefix length.
277 // If the other prefix is within this prefix, the masked address must
278 // be same as the address of this prefix.
279 //
280 IpAddress maskedAddr =
281 IpAddress.makeMaskedAddress(other, this.prefixLength);
282 return this.address.equals(maskedAddr);
Jonathan Hart70da5122014-10-01 16:37:42 -0700283 }
284
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700285 @Override
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700286 public int hashCode() {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700287 return Objects.hash(address, prefixLength);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700288 }
289
290 @Override
291 public boolean equals(Object obj) {
292 if (this == obj) {
293 return true;
294 }
Pavlin Radoslavov50b70672014-11-05 11:22:25 -0800295 if ((obj == null) || (!(obj instanceof IpPrefix))) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700296 return false;
297 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700298 IpPrefix other = (IpPrefix) obj;
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700299 return ((prefixLength == other.prefixLength) &&
300 address.equals(other.address));
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700301 }
302
303 @Override
304 /*
305 * (non-Javadoc)
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700306 * The format is "x.x.x.x/y" for IPv4 prefixes.
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700307 *
308 * @see java.lang.Object#toString()
309 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700310 public String toString() {
311 final StringBuilder builder = new StringBuilder();
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700312 builder.append(address.toString());
313 builder.append("/");
314 builder.append(String.format("%d", prefixLength));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700315 return builder.toString();
316 }
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -0800317
318 /**
319 * Checks whether the prefix length is valid.
320 *
321 * @param version the IP address version
322 * @param prefixLength the prefix length value to check
323 * @throws IllegalArgumentException if the prefix length value is invalid
324 */
325 private static void checkPrefixLength(IpAddress.Version version,
326 int prefixLength) {
327 int maxPrefixLen = 0;
328
329 switch (version) {
330 case INET:
331 maxPrefixLen = MAX_INET_MASK_LENGTH;
332 break;
333 case INET6:
334 maxPrefixLen = MAX_INET6_MASK_LENGTH;
335 break;
336 default:
337 String msg = "Invalid IP version " + version;
338 throw new IllegalArgumentException(msg);
339 }
340
341 if ((prefixLength < 0) || (prefixLength > maxPrefixLen)) {
342 String msg = "Invalid prefix length " + prefixLength + ". " +
343 "The value must be in the interval [0, " +
344 maxPrefixLen + "]";
345 throw new IllegalArgumentException(msg);
346 }
347 }
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700348}