blob: 3cde79db34160570ea236ce561205f108eb1880d [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 Radoslavovd0e32d72014-10-31 18:11:43 -070079 * @param version the IP address version
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070080 * @param address the IP address value stored in network byte order
81 * @param prefixLength the prefix length
82 * @return an IP prefix
83 */
Pavlin Radoslavovd0e32d72014-10-31 18:11:43 -070084 public static IpPrefix valueOf(IpAddress.Version version, byte[] address,
85 int prefixLength) {
86 return new IpPrefix(IpAddress.valueOf(version, address),
87 prefixLength);
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070088 }
89
90 /**
91 * Converts an IP address and a prefix length into IP prefix.
92 *
93 * @param address the IP address
94 * @param prefixLength the prefix length
95 * @return an IP prefix
96 */
97 public static IpPrefix valueOf(IpAddress address, int prefixLength) {
98 return new IpPrefix(address, prefixLength);
99 }
100
101 /**
102 * Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16") into an
103 * IP prefix.
104 *
Thomas Vachuska4b420772014-10-30 16:46:17 -0700105 * @param address an IP prefix in string form, e.g. "10.1.0.0/16"
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700106 * @return an IP prefix
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700107 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700108 public static IpPrefix valueOf(String address) {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700109 final String[] parts = address.split("/");
110 if (parts.length != 2) {
111 String msg = "Malformed IP prefix string: " + address + "." +
112 "Address must take form \"x.x.x.x/y\"";
113 throw new IllegalArgumentException(msg);
114 }
115 IpAddress ipAddress = IpAddress.valueOf(parts[0]);
116 int prefixLength = Integer.parseInt(parts[1]);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700117
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700118 return new IpPrefix(ipAddress, prefixLength);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700119 }
120
121 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700122 * Returns the IP version of the prefix.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700123 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700124 * @return the IP version of the prefix
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700125 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700126 public IpAddress.Version version() {
127 return address.version();
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700128 }
129
130 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700131 * Returns the IP address value of the prefix.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700132 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700133 * @return the IP address value of the prefix
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700134 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700135 public IpAddress address() {
136 return address;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700137 }
138
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700139 /**
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700140 * Returns the IP address prefix length.
141 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700142 * @return the IP address prefix length
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700143 */
144 public int prefixLength() {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700145 return prefixLength;
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700146 }
147
148 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700149 * Determines whether a given IP prefix is contained within this prefix.
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700150 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700151 * @param other the IP prefix to test
152 * @return true if the other IP prefix is contained in this prefix,
153 * otherwise false
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700154 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700155 public boolean contains(IpPrefix other) {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700156 if (this.prefixLength > other.prefixLength) {
157 return false; // This prefix has smaller prefix size
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700158 }
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700159
160 //
161 // Mask the other address with my prefix length.
162 // If the other prefix is within this prefix, the masked address must
163 // be same as the address of this prefix.
164 //
165 IpAddress maskedAddr =
166 IpAddress.makeMaskedAddress(other.address, this.prefixLength);
167 return this.address.equals(maskedAddr);
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700168 }
169
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700170 /**
171 * Determines whether a given IP address is contained within this prefix.
172 *
173 * @param other the IP address to test
174 * @return true if the IP address is contained in this prefix, otherwise
175 * false
176 */
177 public boolean contains(IpAddress other) {
178 //
179 // Mask the other address with my prefix length.
180 // If the other prefix is within this prefix, the masked address must
181 // be same as the address of this prefix.
182 //
183 IpAddress maskedAddr =
184 IpAddress.makeMaskedAddress(other, this.prefixLength);
185 return this.address.equals(maskedAddr);
Jonathan Hart70da5122014-10-01 16:37:42 -0700186 }
187
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700188 @Override
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700189 public int hashCode() {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700190 return Objects.hash(address, prefixLength);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700191 }
192
193 @Override
194 public boolean equals(Object obj) {
195 if (this == obj) {
196 return true;
197 }
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700198 if ((obj == null) || (getClass() != obj.getClass())) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700199 return false;
200 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700201 IpPrefix other = (IpPrefix) obj;
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700202 return ((prefixLength == other.prefixLength) &&
203 address.equals(other.address));
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700204 }
205
206 @Override
207 /*
208 * (non-Javadoc)
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700209 * The format is "x.x.x.x/y" for IPv4 prefixes.
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700210 *
211 * @see java.lang.Object#toString()
212 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700213 public String toString() {
214 final StringBuilder builder = new StringBuilder();
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700215 builder.append(address.toString());
216 builder.append("/");
217 builder.append(String.format("%d", prefixLength));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700218 return builder.toString();
219 }
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700220}