blob: 4fef5a473f43b075e494903a51e619ecb364a328 [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 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.
23 * <p>
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070024 * NOTE: The stored IP address in the result IP prefix is masked to
25 * contain zeroes in all bits after the prefix length.
Thomas Vachuska4b420772014-10-30 16:46:17 -070026 * </p>
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070027 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070028public final class IpPrefix {
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070029 // Maximum network mask length
30 public static final int MAX_INET_MASK_LENGTH = IpAddress.INET_BIT_LENGTH;
31 public static final int MAX_INET6_MASK_LENGTH = IpAddress.INET6_BIT_LENGTH;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070032
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070033 private final IpAddress address;
34 private final short prefixLength;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070035
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070036 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070037 * Constructor for given IP address, and a prefix length.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070038 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070039 * @param address the IP address
40 * @param prefixLength the prefix length
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070041 * @throws IllegalArgumentException if the prefix length value is invalid
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070042 */
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -080043 private IpPrefix(IpAddress address, int prefixLength) {
44 checkPrefixLength(address.version(), prefixLength);
45 this.address = IpAddress.makeMaskedAddress(address, prefixLength);
46 this.prefixLength = (short) prefixLength;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070047 }
48
49 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070050 * Returns the IP version of the prefix.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070051 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070052 * @return the IP version of the prefix
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070053 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070054 public IpAddress.Version version() {
55 return address.version();
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070056 }
57
58 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070059 * Returns the IP address value of the prefix.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070060 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070061 * @return the IP address value of the prefix
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070062 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070063 public IpAddress address() {
64 return address;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070065 }
66
Ayaka Koshibe16698a32014-09-13 22:19:02 -070067 /**
Yuta HIGUCHI10681f62014-09-21 17:49:46 -070068 * Returns the IP address prefix length.
69 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070070 * @return the IP address prefix length
Yuta HIGUCHI10681f62014-09-21 17:49:46 -070071 */
72 public int prefixLength() {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070073 return prefixLength;
Yuta HIGUCHI10681f62014-09-21 17:49:46 -070074 }
75
76 /**
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -080077 * Converts an integer and a prefix length into an IPv4 prefix.
78 *
79 * @param address an integer representing the IPv4 address
80 * @param prefixLength the prefix length
81 * @return an IP prefix
82 * @throws IllegalArgumentException if the prefix length value is invalid
83 */
84 public static IpPrefix valueOf(int address, int prefixLength) {
85 return new IpPrefix(IpAddress.valueOf(address), prefixLength);
86 }
87
88 /**
89 * Converts a byte array and a prefix length into an IP prefix.
90 *
91 * @param version the IP address version
92 * @param address the IP address value stored in network byte order
93 * @param prefixLength the prefix length
94 * @return an IP prefix
95 * @throws IllegalArgumentException if the prefix length value is invalid
96 */
97 public static IpPrefix valueOf(IpAddress.Version version, byte[] address,
98 int prefixLength) {
99 return new IpPrefix(IpAddress.valueOf(version, address), prefixLength);
100 }
101
102 /**
103 * Converts an IP address and a prefix length into IP prefix.
104 *
105 * @param address the IP address
106 * @param prefixLength the prefix length
107 * @return an IP prefix
108 * @throws IllegalArgumentException if the prefix length value is invalid
109 */
110 public static IpPrefix valueOf(IpAddress address, int prefixLength) {
111 return new IpPrefix(address, prefixLength);
112 }
113
114 /**
115 * Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16") into an
116 * IP prefix.
117 *
118 * @param address an IP prefix in string form, e.g. "10.1.0.0/16"
119 * @return an IP prefix
120 * @throws IllegalArgumentException if the arguments are invalid
121 */
122 public static IpPrefix valueOf(String address) {
123 final String[] parts = address.split("/");
124 if (parts.length != 2) {
125 String msg = "Malformed IP prefix string: " + address + "." +
126 "Address must take form \"x.x.x.x/y\"";
127 throw new IllegalArgumentException(msg);
128 }
129 IpAddress ipAddress = IpAddress.valueOf(parts[0]);
130 int prefixLength = Integer.parseInt(parts[1]);
131
132 return new IpPrefix(ipAddress, prefixLength);
133 }
134
135 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700136 * Determines whether a given IP prefix is contained within this prefix.
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700137 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700138 * @param other the IP prefix to test
139 * @return true if the other IP prefix is contained in this prefix,
140 * otherwise false
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700141 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700142 public boolean contains(IpPrefix other) {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700143 if (this.prefixLength > other.prefixLength) {
144 return false; // This prefix has smaller prefix size
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700145 }
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700146
147 //
148 // Mask the other address with my prefix length.
149 // If the other prefix is within this prefix, the masked address must
150 // be same as the address of this prefix.
151 //
152 IpAddress maskedAddr =
153 IpAddress.makeMaskedAddress(other.address, this.prefixLength);
154 return this.address.equals(maskedAddr);
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700155 }
156
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700157 /**
158 * Determines whether a given IP address is contained within this prefix.
159 *
160 * @param other the IP address to test
161 * @return true if the IP address is contained in this prefix, otherwise
162 * false
163 */
164 public boolean contains(IpAddress other) {
165 //
166 // Mask the other address with my prefix length.
167 // If the other prefix is within this prefix, the masked address must
168 // be same as the address of this prefix.
169 //
170 IpAddress maskedAddr =
171 IpAddress.makeMaskedAddress(other, this.prefixLength);
172 return this.address.equals(maskedAddr);
Jonathan Hart70da5122014-10-01 16:37:42 -0700173 }
174
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700175 @Override
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700176 public int hashCode() {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700177 return Objects.hash(address, prefixLength);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700178 }
179
180 @Override
181 public boolean equals(Object obj) {
182 if (this == obj) {
183 return true;
184 }
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700185 if ((obj == null) || (getClass() != obj.getClass())) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700186 return false;
187 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700188 IpPrefix other = (IpPrefix) obj;
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700189 return ((prefixLength == other.prefixLength) &&
190 address.equals(other.address));
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700191 }
192
193 @Override
194 /*
195 * (non-Javadoc)
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700196 * The format is "x.x.x.x/y" for IPv4 prefixes.
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700197 *
198 * @see java.lang.Object#toString()
199 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700200 public String toString() {
201 final StringBuilder builder = new StringBuilder();
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700202 builder.append(address.toString());
203 builder.append("/");
204 builder.append(String.format("%d", prefixLength));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700205 return builder.toString();
206 }
Pavlin Radoslavov34c921a2014-11-03 15:41:22 -0800207
208 /**
209 * Checks whether the prefix length is valid.
210 *
211 * @param version the IP address version
212 * @param prefixLength the prefix length value to check
213 * @throws IllegalArgumentException if the prefix length value is invalid
214 */
215 private static void checkPrefixLength(IpAddress.Version version,
216 int prefixLength) {
217 int maxPrefixLen = 0;
218
219 switch (version) {
220 case INET:
221 maxPrefixLen = MAX_INET_MASK_LENGTH;
222 break;
223 case INET6:
224 maxPrefixLen = MAX_INET6_MASK_LENGTH;
225 break;
226 default:
227 String msg = "Invalid IP version " + version;
228 throw new IllegalArgumentException(msg);
229 }
230
231 if ((prefixLength < 0) || (prefixLength > maxPrefixLen)) {
232 String msg = "Invalid prefix length " + prefixLength + ". " +
233 "The value must be in the interval [0, " +
234 maxPrefixLen + "]";
235 throw new IllegalArgumentException(msg);
236 }
237 }
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700238}