Pavlin Radoslavov

Refactor the IpPrefix API and implementation:

 * Now IpPrefix uses IpAddress to represent the subnet address
 * The IpPrefix subnet address is masked-out by the prefix length.
   E.g., IpPrefix("1.2.3.4/24") is now stored as IpPrefix("1.2.3.0/24")
 * Removed IpPrefix methods that are not used or don't apply anymore
 * Replaced usage of IpPrefix with IpAddress where appropriate
...@@ -36,7 +36,6 @@ import org.onlab.onos.net.host.InterfaceIpAddress; ...@@ -36,7 +36,6 @@ import org.onlab.onos.net.host.InterfaceIpAddress;
36 import org.onlab.onos.net.host.PortAddresses; 36 import org.onlab.onos.net.host.PortAddresses;
37 import org.onlab.packet.IpAddress; 37 import org.onlab.packet.IpAddress;
38 import org.onlab.packet.IpPrefix; 38 import org.onlab.packet.IpPrefix;
39 -import org.onlab.packet.Ip4Prefix;
40 import org.onlab.packet.MacAddress; 39 import org.onlab.packet.MacAddress;
41 import org.slf4j.Logger; 40 import org.slf4j.Logger;
42 41
...@@ -81,12 +80,8 @@ public class NetworkConfigReader { ...@@ -81,12 +80,8 @@ public class NetworkConfigReader {
81 if (splits.length != 2) { 80 if (splits.length != 2) {
82 throw new IllegalArgumentException("Invalid IP address and prefix length format"); 81 throw new IllegalArgumentException("Invalid IP address and prefix length format");
83 } 82 }
84 - // 83 + // NOTE: IpPrefix will mask-out the bits after the prefix length.
85 - // TODO: For now we need Ip4Prefix to mask-out the 84 + IpPrefix subnet = IpPrefix.valueOf(strIp);
86 - // subnet address.
87 - //
88 - Ip4Prefix subnet4 = new Ip4Prefix(strIp);
89 - IpPrefix subnet = IpPrefix.valueOf(subnet4.toString());
90 IpAddress addr = IpAddress.valueOf(splits[0]); 85 IpAddress addr = IpAddress.valueOf(splits[0]);
91 InterfaceIpAddress ia = 86 InterfaceIpAddress ia =
92 new InterfaceIpAddress(addr, subnet); 87 new InterfaceIpAddress(addr, subnet);
......
...@@ -73,7 +73,7 @@ public class RouteEntry { ...@@ -73,7 +73,7 @@ public class RouteEntry {
73 } 73 }
74 74
75 StringBuilder result = new StringBuilder(ip4Prefix.prefixLength()); 75 StringBuilder result = new StringBuilder(ip4Prefix.prefixLength());
76 - long value = ip4Prefix.toInt(); 76 + long value = ip4Prefix.address().toInt() & 0xffffffffL;
77 for (int i = 0; i < ip4Prefix.prefixLength(); i++) { 77 for (int i = 0; i < ip4Prefix.prefixLength(); i++) {
78 long mask = 1 << (IpPrefix.MAX_INET_MASK_LENGTH - 1 - i); 78 long mask = 1 << (IpPrefix.MAX_INET_MASK_LENGTH - 1 - i);
79 result.append(((value & mask) == 0) ? "0" : "1"); 79 result.append(((value & mask) == 0) ? "0" : "1");
......
...@@ -188,7 +188,7 @@ class TestBgpPeerChannelHandler extends SimpleChannelHandler { ...@@ -188,7 +188,7 @@ class TestBgpPeerChannelHandler extends SimpleChannelHandler {
188 int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up 188 int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
189 message.writeByte(prefixBitlen); 189 message.writeByte(prefixBitlen);
190 190
191 - IpAddress address = prefix.toIpAddress(); 191 + IpAddress address = prefix.address();
192 long value = address.toInt() & 0xffffffffL; 192 long value = address.toInt() & 0xffffffffL;
193 for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) { 193 for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
194 if (prefixBytelen-- == 0) { 194 if (prefixBytelen-- == 0) {
......
...@@ -22,7 +22,7 @@ import java.util.Objects; ...@@ -22,7 +22,7 @@ import java.util.Objects;
22 import org.onlab.onos.net.PortNumber; 22 import org.onlab.onos.net.PortNumber;
23 import org.onlab.onos.net.flow.instructions.Instruction; 23 import org.onlab.onos.net.flow.instructions.Instruction;
24 import org.onlab.onos.net.flow.instructions.Instructions; 24 import org.onlab.onos.net.flow.instructions.Instructions;
25 -import org.onlab.packet.IpPrefix; 25 +import org.onlab.packet.IpAddress;
26 import org.onlab.packet.MacAddress; 26 import org.onlab.packet.MacAddress;
27 import org.onlab.packet.VlanId; 27 import org.onlab.packet.VlanId;
28 28
...@@ -181,12 +181,12 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { ...@@ -181,12 +181,12 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
181 } 181 }
182 182
183 @Override 183 @Override
184 - public Builder setIpSrc(IpPrefix addr) { 184 + public Builder setIpSrc(IpAddress addr) {
185 return add(Instructions.modL3Src(addr)); 185 return add(Instructions.modL3Src(addr));
186 } 186 }
187 187
188 @Override 188 @Override
189 - public Builder setIpDst(IpPrefix addr) { 189 + public Builder setIpDst(IpAddress addr) {
190 return add(Instructions.modL3Dst(addr)); 190 return add(Instructions.modL3Dst(addr));
191 } 191 }
192 192
......
...@@ -19,7 +19,7 @@ import java.util.List; ...@@ -19,7 +19,7 @@ import java.util.List;
19 19
20 import org.onlab.onos.net.PortNumber; 20 import org.onlab.onos.net.PortNumber;
21 import org.onlab.onos.net.flow.instructions.Instruction; 21 import org.onlab.onos.net.flow.instructions.Instruction;
22 -import org.onlab.packet.IpPrefix; 22 +import org.onlab.packet.IpAddress;
23 import org.onlab.packet.MacAddress; 23 import org.onlab.packet.MacAddress;
24 import org.onlab.packet.VlanId; 24 import org.onlab.packet.VlanId;
25 25
...@@ -92,14 +92,14 @@ public interface TrafficTreatment { ...@@ -92,14 +92,14 @@ public interface TrafficTreatment {
92 * @param addr an ip 92 * @param addr an ip
93 * @return a treatment builder 93 * @return a treatment builder
94 */ 94 */
95 - public Builder setIpSrc(IpPrefix addr); 95 + public Builder setIpSrc(IpAddress addr);
96 96
97 /** 97 /**
98 * Sets the dst l3 address. 98 * Sets the dst l3 address.
99 * @param addr an ip 99 * @param addr an ip
100 * @return a treatment builder 100 * @return a treatment builder
101 */ 101 */
102 - public Builder setIpDst(IpPrefix addr); 102 + public Builder setIpDst(IpAddress addr);
103 103
104 /** 104 /**
105 * Sets the optical channel ID or lambda. 105 * Sets the optical channel ID or lambda.
......
...@@ -27,7 +27,7 @@ import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.L2SubType; ...@@ -27,7 +27,7 @@ import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.L2SubType;
27 import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; 27 import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
28 import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.L3SubType; 28 import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.L3SubType;
29 import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction; 29 import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
30 -import org.onlab.packet.IpPrefix; 30 +import org.onlab.packet.IpAddress;
31 import org.onlab.packet.MacAddress; 31 import org.onlab.packet.MacAddress;
32 import org.onlab.packet.VlanId; 32 import org.onlab.packet.VlanId;
33 33
...@@ -115,7 +115,7 @@ public final class Instructions { ...@@ -115,7 +115,7 @@ public final class Instructions {
115 * @param addr the ip address to modify to. 115 * @param addr the ip address to modify to.
116 * @return a L3 modification 116 * @return a L3 modification
117 */ 117 */
118 - public static L3ModificationInstruction modL3Src(IpPrefix addr) { 118 + public static L3ModificationInstruction modL3Src(IpAddress addr) {
119 checkNotNull(addr, "Src l3 address cannot be null"); 119 checkNotNull(addr, "Src l3 address cannot be null");
120 return new ModIPInstruction(L3SubType.IP_SRC, addr); 120 return new ModIPInstruction(L3SubType.IP_SRC, addr);
121 } 121 }
...@@ -125,7 +125,7 @@ public final class Instructions { ...@@ -125,7 +125,7 @@ public final class Instructions {
125 * @param addr the ip address to modify to. 125 * @param addr the ip address to modify to.
126 * @return a L3 modification 126 * @return a L3 modification
127 */ 127 */
128 - public static L3ModificationInstruction modL3Dst(IpPrefix addr) { 128 + public static L3ModificationInstruction modL3Dst(IpAddress addr) {
129 checkNotNull(addr, "Dst l3 address cannot be null"); 129 checkNotNull(addr, "Dst l3 address cannot be null");
130 return new ModIPInstruction(L3SubType.IP_DST, addr); 130 return new ModIPInstruction(L3SubType.IP_DST, addr);
131 } 131 }
......
...@@ -19,7 +19,7 @@ import static com.google.common.base.MoreObjects.toStringHelper; ...@@ -19,7 +19,7 @@ import static com.google.common.base.MoreObjects.toStringHelper;
19 19
20 import java.util.Objects; 20 import java.util.Objects;
21 21
22 -import org.onlab.packet.IpPrefix; 22 +import org.onlab.packet.IpAddress;
23 23
24 /** 24 /**
25 * Abstraction of a single traffic treatment step. 25 * Abstraction of a single traffic treatment step.
...@@ -60,9 +60,9 @@ public abstract class L3ModificationInstruction implements Instruction { ...@@ -60,9 +60,9 @@ public abstract class L3ModificationInstruction implements Instruction {
60 public static final class ModIPInstruction extends L3ModificationInstruction { 60 public static final class ModIPInstruction extends L3ModificationInstruction {
61 61
62 private final L3SubType subtype; 62 private final L3SubType subtype;
63 - private final IpPrefix ip; 63 + private final IpAddress ip;
64 64
65 - public ModIPInstruction(L3SubType subType, IpPrefix addr) { 65 + public ModIPInstruction(L3SubType subType, IpAddress addr) {
66 66
67 this.subtype = subType; 67 this.subtype = subType;
68 this.ip = addr; 68 this.ip = addr;
...@@ -73,7 +73,7 @@ public abstract class L3ModificationInstruction implements Instruction { ...@@ -73,7 +73,7 @@ public abstract class L3ModificationInstruction implements Instruction {
73 return this.subtype; 73 return this.subtype;
74 } 74 }
75 75
76 - public IpPrefix ip() { 76 + public IpAddress ip() {
77 return this.ip; 77 return this.ip;
78 } 78 }
79 79
......
...@@ -38,7 +38,7 @@ public final class IpPrefixSerializer extends Serializer<IpPrefix> { ...@@ -38,7 +38,7 @@ public final class IpPrefixSerializer extends Serializer<IpPrefix> {
38 @Override 38 @Override
39 public void write(Kryo kryo, Output output, 39 public void write(Kryo kryo, Output output,
40 IpPrefix object) { 40 IpPrefix object) {
41 - byte[] octs = object.toOctets(); 41 + byte[] octs = object.address().toOctets();
42 output.writeInt(octs.length); 42 output.writeInt(octs.length);
43 output.writeBytes(octs); 43 output.writeBytes(octs);
44 output.writeInt(object.prefixLength()); 44 output.writeInt(object.prefixLength());
......
...@@ -31,6 +31,7 @@ import org.onlab.onos.net.flow.FlowRule; ...@@ -31,6 +31,7 @@ import org.onlab.onos.net.flow.FlowRule;
31 import org.onlab.onos.net.flow.TrafficSelector; 31 import org.onlab.onos.net.flow.TrafficSelector;
32 import org.onlab.onos.net.flow.TrafficTreatment; 32 import org.onlab.onos.net.flow.TrafficTreatment;
33 import org.onlab.onos.openflow.controller.Dpid; 33 import org.onlab.onos.openflow.controller.Dpid;
34 +import org.onlab.packet.IpAddress;
34 import org.onlab.packet.IpPrefix; 35 import org.onlab.packet.IpPrefix;
35 import org.onlab.packet.MacAddress; 36 import org.onlab.packet.MacAddress;
36 import org.onlab.packet.VlanId; 37 import org.onlab.packet.VlanId;
...@@ -167,24 +168,12 @@ public class FlowEntryBuilder { ...@@ -167,24 +168,12 @@ public class FlowEntryBuilder {
167 case SET_NW_DST: 168 case SET_NW_DST:
168 OFActionSetNwDst nwdst = (OFActionSetNwDst) act; 169 OFActionSetNwDst nwdst = (OFActionSetNwDst) act;
169 IPv4Address di = nwdst.getNwAddr(); 170 IPv4Address di = nwdst.getNwAddr();
170 - if (di.isCidrMask()) { 171 + builder.setIpDst(IpAddress.valueOf(di.getInt()));
171 - builder.setIpDst(IpPrefix.valueOf(di.getInt(),
172 - di.asCidrMaskLength()));
173 - } else {
174 - builder.setIpDst(IpPrefix.valueOf(di.getInt(),
175 - IpPrefix.MAX_INET_MASK_LENGTH));
176 - }
177 break; 172 break;
178 case SET_NW_SRC: 173 case SET_NW_SRC:
179 OFActionSetNwSrc nwsrc = (OFActionSetNwSrc) act; 174 OFActionSetNwSrc nwsrc = (OFActionSetNwSrc) act;
180 IPv4Address si = nwsrc.getNwAddr(); 175 IPv4Address si = nwsrc.getNwAddr();
181 - if (si.isCidrMask()) { 176 + builder.setIpSrc(IpAddress.valueOf(si.getInt()));
182 - builder.setIpSrc(IpPrefix.valueOf(si.getInt(),
183 - si.asCidrMaskLength()));
184 - } else {
185 - builder.setIpSrc(IpPrefix.valueOf(si.getInt(),
186 - IpPrefix.MAX_INET_MASK_LENGTH));
187 - }
188 break; 177 break;
189 case EXPERIMENTER: 178 case EXPERIMENTER:
190 OFActionExperimenter exp = (OFActionExperimenter) act; 179 OFActionExperimenter exp = (OFActionExperimenter) act;
......
...@@ -29,6 +29,8 @@ import org.onlab.onos.net.flow.criteria.Criteria.TcpPortCriterion; ...@@ -29,6 +29,8 @@ import org.onlab.onos.net.flow.criteria.Criteria.TcpPortCriterion;
29 import org.onlab.onos.net.flow.criteria.Criteria.VlanIdCriterion; 29 import org.onlab.onos.net.flow.criteria.Criteria.VlanIdCriterion;
30 import org.onlab.onos.net.flow.criteria.Criteria.VlanPcpCriterion; 30 import org.onlab.onos.net.flow.criteria.Criteria.VlanPcpCriterion;
31 import org.onlab.onos.net.flow.criteria.Criterion; 31 import org.onlab.onos.net.flow.criteria.Criterion;
32 +import org.onlab.packet.IpAddress;
33 +import org.onlab.packet.IpPrefix;
32 import org.projectfloodlight.openflow.protocol.OFFactory; 34 import org.projectfloodlight.openflow.protocol.OFFactory;
33 import org.projectfloodlight.openflow.protocol.OFFlowAdd; 35 import org.projectfloodlight.openflow.protocol.OFFlowAdd;
34 import org.projectfloodlight.openflow.protocol.OFFlowDelete; 36 import org.projectfloodlight.openflow.protocol.OFFlowDelete;
...@@ -141,22 +143,30 @@ public abstract class FlowModBuilder { ...@@ -141,22 +143,30 @@ public abstract class FlowModBuilder {
141 break; 143 break;
142 case IPV4_DST: 144 case IPV4_DST:
143 ip = (IPCriterion) c; 145 ip = (IPCriterion) c;
144 - if (ip.ip().isMasked()) { 146 + if (ip.ip().prefixLength() != IpPrefix.MAX_INET_MASK_LENGTH) {
145 - Masked<IPv4Address> maskedIp = Masked.of(IPv4Address.of(ip.ip().toInt()), 147 + IpAddress maskAddr =
146 - IPv4Address.of(ip.ip().netmask().toInt())); 148 + IpAddress.makeMaskPrefix(ip.ip().prefixLength());
149 + Masked<IPv4Address> maskedIp =
150 + Masked.of(IPv4Address.of(ip.ip().address().toInt()),
151 + IPv4Address.of(maskAddr.toInt()));
147 mBuilder.setMasked(MatchField.IPV4_DST, maskedIp); 152 mBuilder.setMasked(MatchField.IPV4_DST, maskedIp);
148 } else { 153 } else {
149 - mBuilder.setExact(MatchField.IPV4_DST, IPv4Address.of(ip.ip().toInt())); 154 + mBuilder.setExact(MatchField.IPV4_DST,
155 + IPv4Address.of(ip.ip().address().toInt()));
150 } 156 }
151 break; 157 break;
152 case IPV4_SRC: 158 case IPV4_SRC:
153 ip = (IPCriterion) c; 159 ip = (IPCriterion) c;
154 - if (ip.ip().isMasked()) { 160 + if (ip.ip().prefixLength() != IpPrefix.MAX_INET_MASK_LENGTH) {
155 - Masked<IPv4Address> maskedIp = Masked.of(IPv4Address.of(ip.ip().toInt()), 161 + IpAddress maskAddr =
156 - IPv4Address.of(ip.ip().netmask().toInt())); 162 + IpAddress.makeMaskPrefix(ip.ip().prefixLength());
163 + Masked<IPv4Address> maskedIp =
164 + Masked.of(IPv4Address.of(ip.ip().address().toInt()),
165 + IPv4Address.of(maskAddr.toInt()));
157 mBuilder.setMasked(MatchField.IPV4_SRC, maskedIp); 166 mBuilder.setMasked(MatchField.IPV4_SRC, maskedIp);
158 } else { 167 } else {
159 - mBuilder.setExact(MatchField.IPV4_SRC, IPv4Address.of(ip.ip().toInt())); 168 + mBuilder.setExact(MatchField.IPV4_SRC,
169 + IPv4Address.of(ip.ip().address().toInt()));
160 } 170 }
161 break; 171 break;
162 case IP_PROTO: 172 case IP_PROTO:
......
...@@ -21,7 +21,8 @@ import java.util.Objects; ...@@ -21,7 +21,8 @@ import java.util.Objects;
21 import static com.google.common.base.Preconditions.checkNotNull; 21 import static com.google.common.base.Preconditions.checkNotNull;
22 22
23 /** 23 /**
24 - * A class representing an IPv4 address. 24 + * A class representing an IP address.
25 + * TODO: Add support for IPv6 as well.
25 */ 26 */
26 public final class IpAddress implements Comparable<IpAddress> { 27 public final class IpAddress implements Comparable<IpAddress> {
27 // IP Versions 28 // IP Versions
...@@ -44,8 +45,6 @@ public final class IpAddress implements Comparable<IpAddress> { ...@@ -44,8 +45,6 @@ public final class IpAddress implements Comparable<IpAddress> {
44 * @param value the IP address value 45 * @param value the IP address value
45 */ 46 */
46 private IpAddress(Version version, byte[] value) { 47 private IpAddress(Version version, byte[] value) {
47 - checkNotNull(value);
48 -
49 this.version = version; 48 this.version = version;
50 this.octets = Arrays.copyOf(value, INET_BYTE_LENGTH); 49 this.octets = Arrays.copyOf(value, INET_BYTE_LENGTH);
51 } 50 }
...@@ -53,7 +52,7 @@ public final class IpAddress implements Comparable<IpAddress> { ...@@ -53,7 +52,7 @@ public final class IpAddress implements Comparable<IpAddress> {
53 /** 52 /**
54 * Converts an integer into an IPv4 address. 53 * Converts an integer into an IPv4 address.
55 * 54 *
56 - * @param value an integer representing an IPv4 value 55 + * @param value an integer representing an IPv4 address value
57 * @return an IP address 56 * @return an IP address
58 */ 57 */
59 public static IpAddress valueOf(int value) { 58 public static IpAddress valueOf(int value) {
...@@ -70,6 +69,7 @@ public final class IpAddress implements Comparable<IpAddress> { ...@@ -70,6 +69,7 @@ public final class IpAddress implements Comparable<IpAddress> {
70 * @return an IP address 69 * @return an IP address
71 */ 70 */
72 public static IpAddress valueOf(byte[] value) { 71 public static IpAddress valueOf(byte[] value) {
72 + checkNotNull(value);
73 return new IpAddress(Version.INET, value); 73 return new IpAddress(Version.INET, value);
74 } 74 }
75 75
...@@ -106,13 +106,13 @@ public final class IpAddress implements Comparable<IpAddress> { ...@@ -106,13 +106,13 @@ public final class IpAddress implements Comparable<IpAddress> {
106 /** 106 /**
107 * Converts a dotted-decimal string (x.x.x.x) into an IPv4 address. 107 * Converts a dotted-decimal string (x.x.x.x) into an IPv4 address.
108 * 108 *
109 - * @param address a IP address in string form, e.g. "10.0.0.1". 109 + * @param address an IP address in string form, e.g. "10.0.0.1"
110 * @return an IP address 110 * @return an IP address
111 */ 111 */
112 public static IpAddress valueOf(String address) { 112 public static IpAddress valueOf(String address) {
113 final String[] net = address.split("\\."); 113 final String[] net = address.split("\\.");
114 if (net.length != INET_BYTE_LENGTH) { 114 if (net.length != INET_BYTE_LENGTH) {
115 - String msg = "Malformed IPv4 address string; " + 115 + String msg = "Malformed IPv4 address string: " + address + "." +
116 "Address must have four decimal values separated by dots (.)"; 116 "Address must have four decimal values separated by dots (.)";
117 throw new IllegalArgumentException(msg); 117 throw new IllegalArgumentException(msg);
118 } 118 }
...@@ -154,20 +154,21 @@ public final class IpAddress implements Comparable<IpAddress> { ...@@ -154,20 +154,21 @@ public final class IpAddress implements Comparable<IpAddress> {
154 /** 154 /**
155 * Creates an IP network mask prefix. 155 * Creates an IP network mask prefix.
156 * 156 *
157 - * @param prefixLen the length of the mask prefix. Must be in the interval 157 + * @param prefixLength the length of the mask prefix. Must be in the
158 - * [0, 32] for IPv4 158 + * interval [0, 32] for IPv4
159 * @return a new IP address that contains a mask prefix of the 159 * @return a new IP address that contains a mask prefix of the
160 * specified length 160 * specified length
161 */ 161 */
162 - public static IpAddress makeMaskPrefix(int prefixLen) { 162 + public static IpAddress makeMaskPrefix(int prefixLength) {
163 // Verify the prefix length 163 // Verify the prefix length
164 - if ((prefixLen < 0) || (prefixLen > INET_BIT_LENGTH)) { 164 + if ((prefixLength < 0) || (prefixLength > INET_BIT_LENGTH)) {
165 - final String msg = "Invalid IPv4 prefix length: " + prefixLen + 165 + final String msg = "Invalid IPv4 prefix length: " + prefixLength +
166 ". Must be in the interval [0, 32]."; 166 ". Must be in the interval [0, 32].";
167 throw new IllegalArgumentException(msg); 167 throw new IllegalArgumentException(msg);
168 } 168 }
169 169
170 - long v = (0xffffffffL << (INET_BIT_LENGTH - prefixLen)) & 0xffffffffL; 170 + long v =
171 + (0xffffffffL << (INET_BIT_LENGTH - prefixLength)) & 0xffffffffL;
171 return IpAddress.valueOf((int) v); 172 return IpAddress.valueOf((int) v);
172 } 173 }
173 174
...@@ -176,14 +177,14 @@ public final class IpAddress implements Comparable<IpAddress> { ...@@ -176,14 +177,14 @@ public final class IpAddress implements Comparable<IpAddress> {
176 * mask length. 177 * mask length.
177 * 178 *
178 * @param addr the address to mask 179 * @param addr the address to mask
179 - * @param prefixLen the length of the mask prefix. Must be in the interval 180 + * @param prefixLength the length of the mask prefix. Must be in the
180 - * [0, 32] for IPv4 181 + * interval [0, 32] for IPv4
181 * @return a new IP address that is masked with a mask prefix of the 182 * @return a new IP address that is masked with a mask prefix of the
182 * specified length 183 * specified length
183 */ 184 */
184 public static IpAddress makeMaskedAddress(final IpAddress addr, 185 public static IpAddress makeMaskedAddress(final IpAddress addr,
185 - int prefixLen) { 186 + int prefixLength) {
186 - IpAddress mask = IpAddress.makeMaskPrefix(prefixLen); 187 + IpAddress mask = IpAddress.makeMaskPrefix(prefixLength);
187 byte[] net = new byte[INET_BYTE_LENGTH]; 188 byte[] net = new byte[INET_BYTE_LENGTH];
188 189
189 // Mask each byte 190 // Mask each byte
...@@ -207,7 +208,7 @@ public final class IpAddress implements Comparable<IpAddress> { ...@@ -207,7 +208,7 @@ public final class IpAddress implements Comparable<IpAddress> {
207 208
208 @Override 209 @Override
209 public boolean equals(Object obj) { 210 public boolean equals(Object obj) {
210 - if (obj == this) { 211 + if (this == obj) {
211 return true; 212 return true;
212 } 213 }
213 if ((obj == null) || (getClass() != obj.getClass())) { 214 if ((obj == null) || (getClass() != obj.getClass())) {
...@@ -221,7 +222,7 @@ public final class IpAddress implements Comparable<IpAddress> { ...@@ -221,7 +222,7 @@ public final class IpAddress implements Comparable<IpAddress> {
221 @Override 222 @Override
222 /* 223 /*
223 * (non-Javadoc) 224 * (non-Javadoc)
224 - * format is "x.x.x.x" for IPv4 addresses. 225 + * The format is "x.x.x.x" for IPv4 addresses.
225 * 226 *
226 * @see java.lang.Object#toString() 227 * @see java.lang.Object#toString()
227 */ 228 */
......
...@@ -15,285 +15,174 @@ ...@@ -15,285 +15,174 @@
15 */ 15 */
16 package org.onlab.packet; 16 package org.onlab.packet;
17 17
18 -import java.util.Arrays; 18 +import java.util.Objects;
19 19
20 /** 20 /**
21 - * A class representing an IPv4 prefix. 21 + * A class representing an IP prefix.
22 + * TODO: Add support for IPv6 as well.
22 * <p/> 23 * <p/>
23 * A prefix consists of an IP address and a subnet mask. 24 * A prefix consists of an IP address and a subnet mask.
25 + * NOTE: The stored IP address in the result IP prefix is masked to
26 + * contain zeroes in all bits after the prefix length.
24 */ 27 */
25 public final class IpPrefix { 28 public final class IpPrefix {
26 -
27 - // TODO a comparator for netmasks? E.g. for sorting by prefix match order.
28 -
29 - // IP Versions: IPv4 and IPv6
30 - public enum Version { INET, INET6 };
31 -
32 // Maximum network mask length 29 // Maximum network mask length
33 public static final int MAX_INET_MASK_LENGTH = IpAddress.INET_BIT_LENGTH; 30 public static final int MAX_INET_MASK_LENGTH = IpAddress.INET_BIT_LENGTH;
34 public static final int MAX_INET6_MASK_LENGTH = IpAddress.INET6_BIT_LENGTH; 31 public static final int MAX_INET6_MASK_LENGTH = IpAddress.INET6_BIT_LENGTH;
35 32
36 - //no mask (no network), e.g. a simple address 33 + private final IpAddress address;
37 - private static final int DEFAULT_MASK = 0; 34 + private final short prefixLength;
38 -
39 - /**
40 - * Default value indicating an unspecified address.
41 - */
42 - private static final byte[] ANY = new byte[] {0, 0, 0, 0};
43 -
44 - private final Version version;
45 - private final byte[] octets;
46 - private final int netmask;
47 -
48 - /**
49 - * Constructor for given IP address version, prefix address octets,
50 - * and network mask length.
51 - *
52 - * @param ver the IP address version
53 - * @param octets the IP prefix address octets
54 - * @param netmask the network mask length
55 - */
56 - private IpPrefix(Version ver, byte[] octets, int netmask) {
57 - this.version = ver;
58 - this.octets = Arrays.copyOf(octets, IpAddress.INET_BYTE_LENGTH);
59 - this.netmask = netmask;
60 - }
61 35
62 /** 36 /**
63 - * Converts a byte array into an IP address. 37 + * Constructor for given IP address, and a prefix length.
64 * 38 *
65 - * @param address a byte array 39 + * @param address the IP address
66 - * @param netmask the CIDR value subnet mask 40 + * @param prefixLength the prefix length
67 - * @return an IP address
68 */ 41 */
69 - public static IpPrefix valueOf(byte[] address, int netmask) { 42 + private IpPrefix(IpAddress address, int prefixLength) {
70 - return new IpPrefix(Version.INET, address, netmask); 43 + checkPrefixLength(prefixLength);
44 + this.address = IpAddress.makeMaskedAddress(address, prefixLength);
45 + this.prefixLength = (short) prefixLength;
71 } 46 }
72 47
73 /** 48 /**
74 - * Helper to convert an integer into a byte array. 49 + * Checks whether the prefix length is valid.
75 * 50 *
76 - * @param address the integer to convert 51 + * @param prefixLength the prefix length value to check
77 - * @return a byte array 52 + * @throws IllegalArgumentException if the prefix length value is invalid
78 */ 53 */
79 - private static byte[] bytes(int address) { 54 + private static void checkPrefixLength(int prefixLength) {
80 - byte[] bytes = new byte [IpAddress.INET_BYTE_LENGTH]; 55 + if ((prefixLength < 0) || (prefixLength > MAX_INET_MASK_LENGTH)) {
81 - for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) { 56 + String msg = "Invalid prefix length " + prefixLength + ". " +
82 - bytes[i] = (byte) ((address >> (IpAddress.INET_BYTE_LENGTH 57 + "The value must be in the interval [0, " +
83 - - (i + 1)) * 8) & 0xff); 58 + MAX_INET_MASK_LENGTH + "]";
59 + throw new IllegalArgumentException(msg);
84 } 60 }
85 -
86 - return bytes;
87 } 61 }
88 62
89 /** 63 /**
90 - * Converts an integer into an IPv4 address. 64 + * Converts an integer and a prefix length into an IPv4 prefix.
91 * 65 *
92 - * @param address an integer representing an IP value 66 + * @param address an integer representing the IPv4 address
93 - * @param netmask the CIDR value subnet mask 67 + * @param prefixLength the prefix length
94 - * @return an IP address 68 + * @return an IP prefix
95 */ 69 */
96 - public static IpPrefix valueOf(int address, int netmask) { 70 + public static IpPrefix valueOf(int address, int prefixLength) {
97 - return new IpPrefix(Version.INET, bytes(address), netmask); 71 + return new IpPrefix(IpAddress.valueOf(address), prefixLength);
98 } 72 }
99 73
100 /** 74 /**
101 - * Converts a dotted-decimal string (x.x.x.x) into an IPv4 address. The 75 + * Converts a byte array and a prefix length into an IP prefix.
102 - * string can also be in CIDR (slash) notation. If the netmask is omitted,
103 - * it will be set to DEFAULT_MASK (0).
104 * 76 *
105 - * @param address a IP address in string form, e.g. "10.0.0.1", "10.0.0.1/24" 77 + * @param address the IP address value stored in network byte order
106 - * @return an IP address 78 + * @param prefixLength the prefix length
79 + * @return an IP prefix
107 */ 80 */
108 - public static IpPrefix valueOf(String address) { 81 + public static IpPrefix valueOf(byte[] address, int prefixLength) {
109 - 82 + return new IpPrefix(IpAddress.valueOf(address), prefixLength);
110 - final String[] parts = address.split("\\/");
111 - if (parts.length > 2) {
112 - throw new IllegalArgumentException("Malformed IP address string; "
113 - + "Address must take form \"x.x.x.x\" or \"x.x.x.x/y\"");
114 - }
115 -
116 - int mask = DEFAULT_MASK;
117 - if (parts.length == 2) {
118 - mask = Integer.parseInt(parts[1]);
119 - if (mask > MAX_INET_MASK_LENGTH) {
120 - throw new IllegalArgumentException(
121 - "Value of subnet mask cannot exceed "
122 - + MAX_INET_MASK_LENGTH);
123 - }
124 - }
125 -
126 - final String[] net = parts[0].split("\\.");
127 - if (net.length != IpAddress.INET_BYTE_LENGTH) {
128 - throw new IllegalArgumentException("Malformed IP address string; "
129 - + "Address must have four decimal values separated by dots (.)");
130 - }
131 - final byte[] bytes = new byte[IpAddress.INET_BYTE_LENGTH];
132 - for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
133 - bytes[i] = (byte) Short.parseShort(net[i], 10);
134 - }
135 - return new IpPrefix(Version.INET, bytes, mask);
136 } 83 }
137 84
138 /** 85 /**
139 - * Returns the IP version of this address. 86 + * Converts an IP address and a prefix length into IP prefix.
140 * 87 *
141 - * @return the version 88 + * @param address the IP address
89 + * @param prefixLength the prefix length
90 + * @return an IP prefix
142 */ 91 */
143 - public Version version() { 92 + public static IpPrefix valueOf(IpAddress address, int prefixLength) {
144 - return this.version; 93 + return new IpPrefix(address, prefixLength);
145 } 94 }
146 95
147 /** 96 /**
148 - * Returns the IP address as a byte array. 97 + * Converts a CIDR (slash) notation string (e.g., "10.1.0.0/16") into an
98 + * IP prefix.
149 * 99 *
150 - * @return a byte array 100 + * @param value an IP prefix in string form, e.g. "10.1.0.0/16"
101 + * @return an IP prefix
151 */ 102 */
152 - public byte[] toOctets() { 103 + public static IpPrefix valueOf(String address) {
153 - return Arrays.copyOf(this.octets, IpAddress.INET_BYTE_LENGTH); 104 + final String[] parts = address.split("/");
154 - } 105 + if (parts.length != 2) {
155 - 106 + String msg = "Malformed IP prefix string: " + address + "." +
156 - /** 107 + "Address must take form \"x.x.x.x/y\"";
157 - * Returns the IP address prefix length. 108 + throw new IllegalArgumentException(msg);
158 - *
159 - * @return prefix length
160 - */
161 - public int prefixLength() {
162 - return netmask;
163 - }
164 -
165 - /**
166 - * Returns the integral value of this IP address.
167 - *
168 - * @return the IP address's value as an integer
169 - */
170 - public int toInt() {
171 - int val = 0;
172 - for (int i = 0; i < octets.length; i++) {
173 - val <<= 8;
174 - val |= octets[i] & 0xff;
175 - }
176 - return val;
177 } 109 }
110 + IpAddress ipAddress = IpAddress.valueOf(parts[0]);
111 + int prefixLength = Integer.parseInt(parts[1]);
178 112
179 - /** 113 + return new IpPrefix(ipAddress, prefixLength);
180 - * Helper for computing the mask value from CIDR.
181 - *
182 - * @return an integer bitmask
183 - */
184 - private int mask() {
185 - int shift = MAX_INET_MASK_LENGTH - this.netmask;
186 - return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
187 } 114 }
188 115
189 /** 116 /**
190 - * Returns the subnet mask in IpAddress form. 117 + * Returns the IP version of the prefix.
191 * 118 *
192 - * @return the subnet mask as an IpAddress 119 + * @return the IP version of the prefix
193 */ 120 */
194 - public IpAddress netmask() { 121 + public IpAddress.Version version() {
195 - return IpAddress.valueOf(mask()); 122 + return address.version();
196 } 123 }
197 124
198 /** 125 /**
199 - * Returns the network portion of this address as an IpAddress. 126 + * Returns the IP address value of the prefix.
200 - * The netmask of the returned IpAddress is the current mask. If this
201 - * address doesn't have a mask, this returns an all-0 IpAddress.
202 * 127 *
203 - * @return the network address or null 128 + * @return the IP address value of the prefix
204 */ 129 */
205 - public IpPrefix network() { 130 + public IpAddress address() {
206 - if (netmask == DEFAULT_MASK) { 131 + return address;
207 - return new IpPrefix(version, ANY, DEFAULT_MASK);
208 - }
209 -
210 - byte[] net = new byte [4];
211 - byte[] mask = bytes(mask());
212 - for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
213 - net[i] = (byte) (octets[i] & mask[i]);
214 - }
215 - return new IpPrefix(version, net, netmask);
216 } 132 }
217 133
218 /** 134 /**
219 - * Returns the host portion of the IPAddress, as an IPAddress. 135 + * Returns the IP address prefix length.
220 - * The netmask of the returned IpAddress is the current mask. If this
221 - * address doesn't have a mask, this returns a copy of the current
222 - * address.
223 * 136 *
224 - * @return the host address 137 + * @return the IP address prefix length
225 */ 138 */
226 - public IpPrefix host() { 139 + public int prefixLength() {
227 - if (netmask == DEFAULT_MASK) { 140 + return prefixLength;
228 - new IpPrefix(version, octets, netmask);
229 - }
230 -
231 - byte[] host = new byte [IpAddress.INET_BYTE_LENGTH];
232 - byte[] mask = bytes(mask());
233 - for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
234 - host[i] = (byte) (octets[i] & ~mask[i]);
235 - }
236 - return new IpPrefix(version, host, netmask);
237 } 141 }
238 142
239 /** 143 /**
240 - * Returns an IpAddress of the bytes contained in this prefix. 144 + * Determines whether a given IP prefix is contained within this prefix.
241 - * FIXME this is a hack for now and only works because IpPrefix doesn't
242 - * mask the input bytes on creation.
243 * 145 *
244 - * @return the IpAddress 146 + * @param other the IP prefix to test
147 + * @return true if the other IP prefix is contained in this prefix,
148 + * otherwise false
245 */ 149 */
246 - public IpAddress toIpAddress() { 150 + public boolean contains(IpPrefix other) {
247 - return IpAddress.valueOf(octets); 151 + if (this.prefixLength > other.prefixLength) {
152 + return false; // This prefix has smaller prefix size
248 } 153 }
249 154
250 - public boolean isMasked() { 155 + //
251 - return mask() != 0; 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);
252 } 163 }
253 164
254 /** 165 /**
255 - * Determines whether a given address is contained within this IpAddress' 166 + * Determines whether a given IP address is contained within this prefix.
256 - * network.
257 * 167 *
258 - * @param other another IP address that could be contained in this network 168 + * @param other the IP address to test
259 - * @return true if the other IP address is contained in this address' 169 + * @return true if the IP address is contained in this prefix, otherwise
260 - * network, otherwise false 170 + * false
261 */ 171 */
262 - public boolean contains(IpPrefix other) { 172 + public boolean contains(IpAddress other) {
263 - if (this.netmask <= other.netmask) { 173 + //
264 - // Special case where they're both /32 addresses 174 + // Mask the other address with my prefix length.
265 - if (this.netmask == MAX_INET_MASK_LENGTH) { 175 + // If the other prefix is within this prefix, the masked address must
266 - return Arrays.equals(octets, other.octets); 176 + // be same as the address of this prefix.
267 - } 177 + //
268 - 178 + IpAddress maskedAddr =
269 - // Mask the other address with our network mask 179 + IpAddress.makeMaskedAddress(other, this.prefixLength);
270 - IpPrefix otherMasked = 180 + return this.address.equals(maskedAddr);
271 - IpPrefix.valueOf(other.octets, netmask).network();
272 -
273 - return network().equals(otherMasked);
274 - }
275 - return false;
276 - }
277 -
278 - public boolean contains(IpAddress address) {
279 - // Need to get the network address because prefixes aren't automatically
280 - // masked on creation
281 - IpPrefix meMasked = network();
282 -
283 - IpPrefix otherMasked =
284 - IpPrefix.valueOf(address.toOctets(), netmask).network();
285 -
286 - return Arrays.equals(meMasked.octets, otherMasked.octets);
287 } 181 }
288 182
289 @Override 183 @Override
290 public int hashCode() { 184 public int hashCode() {
291 - final int prime = 31; 185 + return Objects.hash(address, prefixLength);
292 - int result = 1;
293 - result = prime * result + netmask;
294 - result = prime * result + Arrays.hashCode(octets);
295 - result = prime * result + ((version == null) ? 0 : version.hashCode());
296 - return result;
297 } 186 }
298 187
299 @Override 188 @Override
...@@ -301,46 +190,26 @@ public final class IpPrefix { ...@@ -301,46 +190,26 @@ public final class IpPrefix {
301 if (this == obj) { 190 if (this == obj) {
302 return true; 191 return true;
303 } 192 }
304 - if (obj == null) { 193 + if ((obj == null) || (getClass() != obj.getClass())) {
305 - return false;
306 - }
307 - if (getClass() != obj.getClass()) {
308 return false; 194 return false;
309 } 195 }
310 IpPrefix other = (IpPrefix) obj; 196 IpPrefix other = (IpPrefix) obj;
311 - if (netmask != other.netmask) { 197 + return ((prefixLength == other.prefixLength) &&
312 - return false; 198 + address.equals(other.address));
313 - }
314 - // TODO not quite right until we mask the input
315 - if (!Arrays.equals(octets, other.octets)) {
316 - return false;
317 - }
318 - if (version != other.version) {
319 - return false;
320 - }
321 - return true;
322 } 199 }
323 200
324 @Override 201 @Override
325 /* 202 /*
326 * (non-Javadoc) 203 * (non-Javadoc)
327 - * format is "x.x.x.x" for non-masked (netmask 0) addresses, 204 + * The format is "x.x.x.x/y" for IPv4 prefixes.
328 - * and "x.x.x.x/y" for masked addresses.
329 * 205 *
330 * @see java.lang.Object#toString() 206 * @see java.lang.Object#toString()
331 */ 207 */
332 public String toString() { 208 public String toString() {
333 final StringBuilder builder = new StringBuilder(); 209 final StringBuilder builder = new StringBuilder();
334 - for (final byte b : this.octets) { 210 + builder.append(address.toString());
335 - if (builder.length() > 0) {
336 - builder.append(".");
337 - }
338 - builder.append(String.format("%d", b & 0xff));
339 - }
340 - if (netmask != DEFAULT_MASK) {
341 builder.append("/"); 211 builder.append("/");
342 - builder.append(String.format("%d", netmask)); 212 + builder.append(String.format("%d", prefixLength));
343 - }
344 return builder.toString(); 213 return builder.toString();
345 } 214 }
346 } 215 }
......
...@@ -22,7 +22,7 @@ import static org.junit.Assert.assertTrue; ...@@ -22,7 +22,7 @@ import static org.junit.Assert.assertTrue;
22 import java.util.Arrays; 22 import java.util.Arrays;
23 23
24 import org.junit.Test; 24 import org.junit.Test;
25 -import org.onlab.packet.IpPrefix.Version; 25 +import org.onlab.packet.IpAddress.Version;
26 26
27 import com.google.common.testing.EqualsTester; 27 import com.google.common.testing.EqualsTester;
28 28
...@@ -30,8 +30,9 @@ public class IpPrefixTest { ...@@ -30,8 +30,9 @@ public class IpPrefixTest {
30 30
31 private static final byte [] BYTES1 = new byte [] {0xa, 0x0, 0x0, 0xa}; 31 private static final byte [] BYTES1 = new byte [] {0xa, 0x0, 0x0, 0xa};
32 private static final byte [] BYTES2 = new byte [] {0xa, 0x0, 0x0, 0xb}; 32 private static final byte [] BYTES2 = new byte [] {0xa, 0x0, 0x0, 0xb};
33 - private static final int INTVAL1 = 167772170; 33 + private static final int INTVAL0 = 0x0a000000;
34 - private static final int INTVAL2 = 167772171; 34 + private static final int INTVAL1 = 0x0a00000a;
35 + private static final int INTVAL2 = 0x0a00000b;
35 private static final String STRVAL = "10.0.0.12/16"; 36 private static final String STRVAL = "10.0.0.12/16";
36 private static final int MASK_LENGTH = 16; 37 private static final int MASK_LENGTH = 16;
37 38
...@@ -59,27 +60,29 @@ public class IpPrefixTest { ...@@ -59,27 +60,29 @@ public class IpPrefixTest {
59 @Test 60 @Test
60 public void basics() { 61 public void basics() {
61 IpPrefix ip1 = IpPrefix.valueOf(BYTES1, MASK_LENGTH); 62 IpPrefix ip1 = IpPrefix.valueOf(BYTES1, MASK_LENGTH);
62 - final byte [] bytes = new byte [] {0xa, 0x0, 0x0, 0xa}; 63 + final byte [] bytes = new byte [] {0xa, 0x0, 0x0, 0x0};
63 64
64 - //check fields 65 + // check fields
65 assertEquals("incorrect IP Version", Version.INET, ip1.version()); 66 assertEquals("incorrect IP Version", Version.INET, ip1.version());
66 assertEquals("incorrect netmask", 16, ip1.prefixLength()); 67 assertEquals("incorrect netmask", 16, ip1.prefixLength());
67 - assertTrue("faulty toOctets()", Arrays.equals(bytes, ip1.toOctets())); 68 + assertTrue("faulty toOctets()",
68 - assertEquals("faulty toInt()", INTVAL1, ip1.toInt()); 69 + Arrays.equals(bytes, ip1.address().toOctets()));
69 - assertEquals("faulty toString()", "10.0.0.10/16", ip1.toString()); 70 + assertEquals("faulty toInt()", INTVAL0, ip1.address().toInt());
71 + assertEquals("faulty toString()", "10.0.0.0/16", ip1.toString());
70 } 72 }
71 73
72 @Test 74 @Test
73 public void netmasks() { 75 public void netmasks() {
74 // masked 76 // masked
75 IpPrefix ip1 = IpPrefix.valueOf(BYTES1, MASK_LENGTH); 77 IpPrefix ip1 = IpPrefix.valueOf(BYTES1, MASK_LENGTH);
76 - 78 + IpPrefix ip2 = IpPrefix.valueOf("10.0.0.10/16");
77 - IpPrefix host = IpPrefix.valueOf("0.0.0.10/16"); 79 + IpPrefix ip3 = IpPrefix.valueOf("10.0.0.0/16");
78 - IpPrefix network = IpPrefix.valueOf("10.0.0.0/16"); 80 + assertEquals("incorrect binary masked address",
79 - assertEquals("incorrect host address", host, ip1.host()); 81 + ip1.toString(), "10.0.0.0/16");
80 - assertEquals("incorrect network address", network, ip1.network()); 82 + assertEquals("incorrect string masked address",
81 - assertEquals("incorrect netmask", "255.255.0.0", ip1.netmask().toString()); 83 + ip2.toString(), "10.0.0.0/16");
82 - 84 + assertEquals("incorrect network address",
85 + ip2.toString(), "10.0.0.0/16");
83 } 86 }
84 87
85 @Test 88 @Test
......