blob: f15946a736a22e2a0a7cdbae2308c1f0c0651cd5 [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/**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070021 * A class representing an IP prefix.
22 * TODO: Add support for IPv6 as well.
Jonathan Hartdec62d42014-09-22 15:59:04 -070023 * <p/>
24 * A prefix consists of an IP address and a subnet mask.
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.
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
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070041 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070042 private IpPrefix(IpAddress address, int prefixLength) {
43 checkPrefixLength(prefixLength);
44 this.address = IpAddress.makeMaskedAddress(address, prefixLength);
45 this.prefixLength = (short) prefixLength;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070046 }
47
48 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070049 * Checks whether the prefix length is valid.
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070050 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070051 * @param prefixLength the prefix length value to check
52 * @throws IllegalArgumentException if the prefix length value is invalid
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070053 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070054 private static void checkPrefixLength(int prefixLength) {
55 if ((prefixLength < 0) || (prefixLength > MAX_INET_MASK_LENGTH)) {
56 String msg = "Invalid prefix length " + prefixLength + ". " +
57 "The value must be in the interval [0, " +
58 MAX_INET_MASK_LENGTH + "]";
59 throw new IllegalArgumentException(msg);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070060 }
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070061 }
62
63 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070064 * Converts an integer and a prefix length into an IPv4 prefix.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -070065 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070066 * @param address an integer representing the IPv4 address
67 * @param prefixLength the prefix length
68 * @return an IP prefix
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070069 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070070 public static IpPrefix valueOf(int address, int prefixLength) {
71 return new IpPrefix(IpAddress.valueOf(address), prefixLength);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070072 }
73
74 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070075 * Converts a byte array and a prefix length into an IP prefix.
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -070076 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -070077 * @param address the IP address value stored in network byte order
78 * @param prefixLength the prefix length
79 * @return an IP prefix
80 */
81 public static IpPrefix valueOf(byte[] address, int prefixLength) {
82 return new IpPrefix(IpAddress.valueOf(address), prefixLength);
83 }
84
85 /**
86 * Converts an IP address and a prefix length into IP prefix.
87 *
88 * @param address the IP address
89 * @param prefixLength the prefix length
90 * @return an IP prefix
91 */
92 public static IpPrefix valueOf(IpAddress address, int prefixLength) {
93 return new IpPrefix(address, prefixLength);
94 }
95
96 /**
97 * Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16") into an
98 * IP prefix.
99 *
100 * @param value an IP prefix in string form, e.g. "10.1.0.0/16"
101 * @return an IP prefix
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700102 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700103 public static IpPrefix valueOf(String address) {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700104 final String[] parts = address.split("/");
105 if (parts.length != 2) {
106 String msg = "Malformed IP prefix string: " + address + "." +
107 "Address must take form \"x.x.x.x/y\"";
108 throw new IllegalArgumentException(msg);
109 }
110 IpAddress ipAddress = IpAddress.valueOf(parts[0]);
111 int prefixLength = Integer.parseInt(parts[1]);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700112
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700113 return new IpPrefix(ipAddress, prefixLength);
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700114 }
115
116 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700117 * Returns the IP version of the prefix.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700118 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700119 * @return the IP version of the prefix
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700120 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700121 public IpAddress.Version version() {
122 return address.version();
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700123 }
124
125 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700126 * Returns the IP address value of the prefix.
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700127 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700128 * @return the IP address value of the prefix
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700129 */
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700130 public IpAddress address() {
131 return address;
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700132 }
133
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700134 /**
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700135 * Returns the IP address prefix length.
136 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700137 * @return the IP address prefix length
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700138 */
139 public int prefixLength() {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700140 return prefixLength;
Yuta HIGUCHI10681f62014-09-21 17:49:46 -0700141 }
142
143 /**
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700144 * Determines whether a given IP prefix is contained within this prefix.
Ayaka Koshibe16698a32014-09-13 22:19:02 -0700145 *
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700146 * @param other the IP prefix to test
147 * @return true if the other IP prefix is contained in this prefix,
148 * otherwise false
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700149 */
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700150 public boolean contains(IpPrefix other) {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700151 if (this.prefixLength > other.prefixLength) {
152 return false; // This prefix has smaller prefix size
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700153 }
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700154
155 //
156 // Mask the other address with my prefix length.
157 // If the other prefix is within this prefix, the masked address must
158 // be same as the address of this prefix.
159 //
160 IpAddress maskedAddr =
161 IpAddress.makeMaskedAddress(other.address, this.prefixLength);
162 return this.address.equals(maskedAddr);
Jonathan Hartb7a2ac32014-09-19 10:42:27 -0700163 }
164
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700165 /**
166 * Determines whether a given IP address is contained within this prefix.
167 *
168 * @param other the IP address to test
169 * @return true if the IP address is contained in this prefix, otherwise
170 * false
171 */
172 public boolean contains(IpAddress other) {
173 //
174 // Mask the other address with my prefix length.
175 // If the other prefix is within this prefix, the masked address must
176 // be same as the address of this prefix.
177 //
178 IpAddress maskedAddr =
179 IpAddress.makeMaskedAddress(other, this.prefixLength);
180 return this.address.equals(maskedAddr);
Jonathan Hart70da5122014-10-01 16:37:42 -0700181 }
182
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700183 @Override
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700184 public int hashCode() {
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700185 return Objects.hash(address, prefixLength);
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700186 }
187
188 @Override
189 public boolean equals(Object obj) {
190 if (this == obj) {
191 return true;
192 }
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700193 if ((obj == null) || (getClass() != obj.getClass())) {
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700194 return false;
195 }
Ayaka Koshibe1d56fe42014-09-19 16:51:58 -0700196 IpPrefix other = (IpPrefix) obj;
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700197 return ((prefixLength == other.prefixLength) &&
198 address.equals(other.address));
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700199 }
200
201 @Override
202 /*
203 * (non-Javadoc)
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700204 * The format is "x.x.x.x/y" for IPv4 prefixes.
Ayaka Koshibe40e7fec2014-09-16 22:32:19 -0700205 *
206 * @see java.lang.Object#toString()
207 */
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700208 public String toString() {
209 final StringBuilder builder = new StringBuilder();
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700210 builder.append(address.toString());
211 builder.append("/");
212 builder.append(String.format("%d", prefixLength));
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700213 return builder.toString();
214 }
Ayaka Koshibe1c7b38e2014-09-11 13:09:51 -0700215}