blob: 180b7711de23b3dd045fc1ab55104dfb22bc8d37 [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
Thomas Vachuska4b420772014-10-30 16:46:17 -070020// TODO: Add support for IPv6 as well.
21
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070022/**
Thomas Vachuska4b420772014-10-30 16:46:17 -070023 * A class representing an IP prefix. A prefix consists of an IP address and
24 * a subnet mask.
25 * <p>
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070026 * NOTE: The stored IP address in the result IP prefix is masked to
27 * contain zeroes in all bits after the prefix length.
Thomas Vachuska4b420772014-10-30 16:46:17 -070028 * </p>
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070029 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -070030public final class IpPrefix {
Pavlin Radoslavov52307e62014-10-29 15:07:37 -070031 // Maximum network mask length
32 public static final int MAX_INET_MASK_LENGTH = IpAddress.INET_BIT_LENGTH;
33 public static final int MAX_INET6_MASK_LENGTH = IpAddress.INET6_BIT_LENGTH;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070034
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070035 private final IpAddress address;
36 private final short prefixLength;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070037
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070038 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070039 * Constructor for given IP address, and a prefix length.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070040 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070041 * @param address the IP address
42 * @param prefixLength the prefix length
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070043 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070044 private IpPrefix(IpAddress address, int prefixLength) {
45 checkPrefixLength(prefixLength);
46 this.address = IpAddress.makeMaskedAddress(address, prefixLength);
47 this.prefixLength = (short) prefixLength;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070048 }
49
50 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070051 * Checks whether the prefix length is valid.
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070052 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070053 * @param prefixLength the prefix length value to check
54 * @throws IllegalArgumentException if the prefix length value is invalid
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070055 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070056 private static void checkPrefixLength(int prefixLength) {
57 if ((prefixLength < 0) || (prefixLength > MAX_INET_MASK_LENGTH)) {
58 String msg = "Invalid prefix length " + prefixLength + ". " +
59 "The value must be in the interval [0, " +
60 MAX_INET_MASK_LENGTH + "]";
61 throw new IllegalArgumentException(msg);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070062 }
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070063 }
64
65 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070066 * Converts an integer and a prefix length into an IPv4 prefix.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070067 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070068 * @param address an integer representing the IPv4 address
69 * @param prefixLength the prefix length
70 * @return an IP prefix
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070071 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070072 public static IpPrefix valueOf(int address, int prefixLength) {
73 return new IpPrefix(IpAddress.valueOf(address), prefixLength);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070074 }
75
76 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070077 * Converts a byte array and a prefix length into an IP prefix.
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070078 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070079 * @param address the IP address value stored in network byte order
80 * @param prefixLength the prefix length
81 * @return an IP prefix
82 */
83 public static IpPrefix valueOf(byte[] address, int prefixLength) {
84 return new IpPrefix(IpAddress.valueOf(address), prefixLength);
85 }
86
87 /**
88 * Converts an IP address and a prefix length into IP prefix.
89 *
90 * @param address the IP address
91 * @param prefixLength the prefix length
92 * @return an IP prefix
93 */
94 public static IpPrefix valueOf(IpAddress address, int prefixLength) {
95 return new IpPrefix(address, prefixLength);
96 }
97
98 /**
99 * Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16") into an
100 * IP prefix.
101 *
Thomas Vachuska4b420772014-10-30 16:46:17 -0700102 * @param address an IP prefix in string form, e.g. "10.1.0.0/16"
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700103 * @return an IP prefix
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700104 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700105 public static IpPrefix valueOf(String address) {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700106 final String[] parts = address.split("/");
107 if (parts.length != 2) {
108 String msg = "Malformed IP prefix string: " + address + "." +
109 "Address must take form \"x.x.x.x/y\"";
110 throw new IllegalArgumentException(msg);
111 }
112 IpAddress ipAddress = IpAddress.valueOf(parts[0]);
113 int prefixLength = Integer.parseInt(parts[1]);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700114
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700115 return new IpPrefix(ipAddress, prefixLength);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700116 }
117
118 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700119 * Returns the IP version of the prefix.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700120 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700121 * @return the IP version of the prefix
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700122 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700123 public IpAddress.Version version() {
124 return address.version();
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700125 }
126
127 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700128 * Returns the IP address value of the prefix.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700129 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700130 * @return the IP address value of the prefix
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700131 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700132 public IpAddress address() {
133 return address;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700134 }
135
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700136 /**
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700137 * Returns the IP address prefix length.
138 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700139 * @return the IP address prefix length
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700140 */
141 public int prefixLength() {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700142 return prefixLength;
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700143 }
144
145 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700146 * Determines whether a given IP prefix is contained within this prefix.
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700147 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700148 * @param other the IP prefix to test
149 * @return true if the other IP prefix is contained in this prefix,
150 * otherwise false
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700151 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700152 public boolean contains(IpPrefix other) {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700153 if (this.prefixLength > other.prefixLength) {
154 return false; // This prefix has smaller prefix size
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700155 }
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700156
157 //
158 // Mask the other address with my prefix length.
159 // If the other prefix is within this prefix, the masked address must
160 // be same as the address of this prefix.
161 //
162 IpAddress maskedAddr =
163 IpAddress.makeMaskedAddress(other.address, this.prefixLength);
164 return this.address.equals(maskedAddr);
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700165 }
166
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700167 /**
168 * Determines whether a given IP address is contained within this prefix.
169 *
170 * @param other the IP address to test
171 * @return true if the IP address is contained in this prefix, otherwise
172 * false
173 */
174 public boolean contains(IpAddress other) {
175 //
176 // Mask the other address with my prefix length.
177 // If the other prefix is within this prefix, the masked address must
178 // be same as the address of this prefix.
179 //
180 IpAddress maskedAddr =
181 IpAddress.makeMaskedAddress(other, this.prefixLength);
182 return this.address.equals(maskedAddr);
Jonathan Hart70da5122014-10-01 16:37:42 -0700183 }
184
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700185 @Override
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700186 public int hashCode() {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700187 return Objects.hash(address, prefixLength);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700188 }
189
190 @Override
191 public boolean equals(Object obj) {
192 if (this == obj) {
193 return true;
194 }
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700195 if ((obj == null) || (getClass() != obj.getClass())) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700196 return false;
197 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700198 IpPrefix other = (IpPrefix) obj;
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700199 return ((prefixLength == other.prefixLength) &&
200 address.equals(other.address));
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700201 }
202
203 @Override
204 /*
205 * (non-Javadoc)
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700206 * The format is "x.x.x.x/y" for IPv4 prefixes.
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700207 *
208 * @see java.lang.Object#toString()
209 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700210 public String toString() {
211 final StringBuilder builder = new StringBuilder();
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700212 builder.append(address.toString());
213 builder.append("/");
214 builder.append(String.format("%d", prefixLength));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700215 return builder.toString();
216 }
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700217}