alshabib

merge

...@@ -74,13 +74,12 @@ public class ReactiveForwarding { ...@@ -74,13 +74,12 @@ public class ReactiveForwarding {
74 74
75 @Override 75 @Override
76 public void process(PacketContext context) { 76 public void process(PacketContext context) {
77 - /* 77 + // Stop processing if the packet has been handled, since we
78 - * stop processing if the packet has been handled, 78 + // can't do any more to it.
79 - * we can't do any more to it
80 - */
81 if (context.isHandled()) { 79 if (context.isHandled()) {
82 return; 80 return;
83 } 81 }
82 +
84 InboundPacket pkt = context.inPacket(); 83 InboundPacket pkt = context.inPacket();
85 HostId id = HostId.hostId(pkt.parsed().getDestinationMAC()); 84 HostId id = HostId.hostId(pkt.parsed().getDestinationMAC());
86 85
...@@ -100,7 +99,6 @@ public class ReactiveForwarding { ...@@ -100,7 +99,6 @@ public class ReactiveForwarding {
100 99
101 // Otherwise, get a set of paths that lead from here to the 100 // Otherwise, get a set of paths that lead from here to the
102 // destination edge switch. 101 // destination edge switch.
103 -
104 Set<Path> paths = topologyService.getPaths(topologyService.currentTopology(), 102 Set<Path> paths = topologyService.getPaths(topologyService.currentTopology(),
105 context.inPacket().receivedFrom().deviceId(), 103 context.inPacket().receivedFrom().deviceId(),
106 dst.location().deviceId()); 104 dst.location().deviceId());
...@@ -137,9 +135,8 @@ public class ReactiveForwarding { ...@@ -137,9 +135,8 @@ public class ReactiveForwarding {
137 135
138 // Floods the specified packet. 136 // Floods the specified packet.
139 private void flood(PacketContext context) { 137 private void flood(PacketContext context) {
140 - boolean canBcast = topologyService.isBroadcastPoint(topologyService.currentTopology(), 138 + if (topologyService.isBroadcastPoint(topologyService.currentTopology(),
141 - context.inPacket().receivedFrom()); 139 + context.inPacket().receivedFrom())) {
142 - if (canBcast) {
143 packetOutFlood(context); 140 packetOutFlood(context);
144 } else { 141 } else {
145 context.block(); 142 context.block();
...@@ -173,6 +170,10 @@ public class ReactiveForwarding { ...@@ -173,6 +170,10 @@ public class ReactiveForwarding {
173 170
174 flowRuleService.applyFlowRules(f); 171 flowRuleService.applyFlowRules(f);
175 172
173 + // we don't yet support bufferids in the flowservice so packet out and
174 + // then install a flowmod.
175 + context.treatmentBuilder().add(Instructions.createOutput(portNumber));
176 + context.send();
176 } 177 }
177 178
178 } 179 }
......
1 package org.onlab.onos.net; 1 package org.onlab.onos.net;
2 2
3 -import java.util.Objects;
4 -
5 /** 3 /**
6 * Representation of a network edge location where an end-station host is 4 * Representation of a network edge location where an end-station host is
7 * connected. 5 * connected.
8 */ 6 */
9 public class HostLocation extends ConnectPoint { 7 public class HostLocation extends ConnectPoint {
10 8
9 + // Note that time is explicitly excluded from the notion of equality.
11 private final long time; 10 private final long time;
12 11
13 public HostLocation(DeviceId deviceId, PortNumber portNumber, long time) { 12 public HostLocation(DeviceId deviceId, PortNumber portNumber, long time) {
...@@ -25,18 +24,4 @@ public class HostLocation extends ConnectPoint { ...@@ -25,18 +24,4 @@ public class HostLocation extends ConnectPoint {
25 return time; 24 return time;
26 } 25 }
27 26
28 - @Override
29 - public int hashCode() {
30 - return 31 * super.hashCode() + Objects.hash(time);
31 - }
32 -
33 - @Override
34 - public boolean equals(Object obj) {
35 - if (obj instanceof HostLocation) {
36 - final HostLocation other = (HostLocation) obj;
37 - return super.equals(obj) && Objects.equals(this.time, other.time);
38 - }
39 - return false;
40 - }
41 -
42 } 27 }
......
...@@ -43,7 +43,6 @@ public interface HostService { ...@@ -43,7 +43,6 @@ public interface HostService {
43 * @param vlanId vlan identifier 43 * @param vlanId vlan identifier
44 * @return set of hosts in the given vlan id 44 * @return set of hosts in the given vlan id
45 */ 45 */
46 - // FIXME: change long to VLanId
47 Set<Host> getHostsByVlan(VlanId vlanId); 46 Set<Host> getHostsByVlan(VlanId vlanId);
48 47
49 /** 48 /**
...@@ -62,6 +61,8 @@ public interface HostService { ...@@ -62,6 +61,8 @@ public interface HostService {
62 */ 61 */
63 Set<Host> getHostsByIp(IpAddress ip); 62 Set<Host> getHostsByIp(IpAddress ip);
64 63
64 + // TODO: consider adding Host getHostByIp(IpAddress ip, VlanId vlan);
65 +
65 /** 66 /**
66 * Returns the set of hosts whose most recent location is the specified 67 * Returns the set of hosts whose most recent location is the specified
67 * connection point. 68 * connection point.
......
1 /** 1 /**
2 - * Core subsystem for tracking infrastructure devices. 2 + * Core subsystem for tracking global inventory of infrastructure devices.
3 */ 3 */
4 package org.onlab.onos.net.trivial.device.impl; 4 package org.onlab.onos.net.trivial.device.impl;
......
1 +/**
2 + * Core subsystem for tracking and manipulating global flow state.
3 + */
4 +package org.onlab.onos.net.trivial.flow.impl;
...@@ -76,14 +76,14 @@ public class SimpleHostStore { ...@@ -76,14 +76,14 @@ public class SimpleHostStore {
76 HostDescription descr) { 76 HostDescription descr) {
77 DefaultHost updated; 77 DefaultHost updated;
78 HostEvent event; 78 HostEvent event;
79 - // Consider only actual location (not timestamp) change? 79 + if (!host.location().equals(descr.location())) {
80 - if (!(host.location().port().equals(descr.location().port()))) {
81 updated = new DefaultHost(providerId, host.id(), 80 updated = new DefaultHost(providerId, host.id(),
82 host.mac(), 81 host.mac(),
83 host.vlan(), 82 host.vlan(),
84 descr.location(), 83 descr.location(),
85 host.ipAddresses()); 84 host.ipAddresses());
86 event = new HostEvent(HOST_MOVED, updated); 85 event = new HostEvent(HOST_MOVED, updated);
86 +
87 } else if (!(host.ipAddresses().equals(descr.ipAddresses()))) { 87 } else if (!(host.ipAddresses().equals(descr.ipAddresses()))) {
88 updated = new DefaultHost(providerId, host.id(), 88 updated = new DefaultHost(providerId, host.id(),
89 host.mac(), 89 host.mac(),
...@@ -134,7 +134,7 @@ public class SimpleHostStore { ...@@ -134,7 +134,7 @@ public class SimpleHostStore {
134 * @return iterable collection of all hosts 134 * @return iterable collection of all hosts
135 */ 135 */
136 Iterable<Host> getHosts() { 136 Iterable<Host> getHosts() {
137 - return Collections.unmodifiableSet(new HashSet<Host>(hosts.values())); 137 + return Collections.unmodifiableSet(new HashSet<>(hosts.values()));
138 } 138 }
139 139
140 /** 140 /**
...@@ -154,7 +154,7 @@ public class SimpleHostStore { ...@@ -154,7 +154,7 @@ public class SimpleHostStore {
154 * @return set of hosts in the vlan 154 * @return set of hosts in the vlan
155 */ 155 */
156 Set<Host> getHosts(VlanId vlanId) { 156 Set<Host> getHosts(VlanId vlanId) {
157 - Set<Host> vlanset = new HashSet<Host>(); 157 + Set<Host> vlanset = new HashSet<>();
158 for (Host h : hosts.values()) { 158 for (Host h : hosts.values()) {
159 if (h.vlan().equals(vlanId)) { 159 if (h.vlan().equals(vlanId)) {
160 vlanset.add(h); 160 vlanset.add(h);
......
1 /** 1 /**
2 - * Core subsystem for tracking edn-station hosts. 2 + * Core subsystem for tracking global inventory of end-station hosts.
3 */ 3 */
4 package org.onlab.onos.net.trivial.host.impl; 4 package org.onlab.onos.net.trivial.host.impl;
......
1 /** 1 /**
2 - * Core subsystem for tracking infrastructure links. 2 + * Core subsystem for tracking global inventory of infrastructure links.
3 */ 3 */
4 package org.onlab.onos.net.trivial.link.impl; 4 package org.onlab.onos.net.trivial.link.impl;
......
1 /** 1 /**
2 * Core subsystem for processing inbound packets and emitting outbound packets. 2 * Core subsystem for processing inbound packets and emitting outbound packets.
3 + * Processing of inbound packets is always in the local context only, but
4 + * emitting outbound packets allows for cluster-wide operation.
3 */ 5 */
4 package org.onlab.onos.net.trivial.packet.impl; 6 package org.onlab.onos.net.trivial.packet.impl;
......
...@@ -142,6 +142,15 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -142,6 +142,15 @@ public class DefaultTopology extends AbstractModel implements Topology {
142 return clusters.get(clusterId); 142 return clusters.get(clusterId);
143 } 143 }
144 144
145 + /**
146 + * Returns the topology cluster that contains the given device.
147 + *
148 + * @param deviceId device identifier
149 + * @return topology cluster
150 + */
151 + TopologyCluster getCluster(DeviceId deviceId) {
152 + return clustersByDevice.get(deviceId);
153 + }
145 154
146 /** 155 /**
147 * Returns the set of cluster devices. 156 * Returns the set of cluster devices.
...@@ -174,13 +183,13 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -174,13 +183,13 @@ public class DefaultTopology extends AbstractModel implements Topology {
174 } 183 }
175 184
176 /** 185 /**
177 - * Indicates whether the given point is part of a broadcast tree. 186 + * Indicates whether the given point is part of a broadcast set.
178 * 187 *
179 * @param connectPoint connection point 188 * @param connectPoint connection point
180 - * @return true if in broadcast tree 189 + * @return true if in broadcast set
181 */ 190 */
182 - boolean isInBroadcastTree(ConnectPoint connectPoint) { 191 + boolean isBroadcastPoint(ConnectPoint connectPoint) {
183 - // Any non-infrastructure, i.e. edge points are assumed to be OK 192 + // Any non-infrastructure, i.e. edge points are assumed to be OK.
184 if (!isInfrastructure(connectPoint)) { 193 if (!isInfrastructure(connectPoint)) {
185 return true; 194 return true;
186 } 195 }
...@@ -191,13 +200,23 @@ public class DefaultTopology extends AbstractModel implements Topology { ...@@ -191,13 +200,23 @@ public class DefaultTopology extends AbstractModel implements Topology {
191 throw new IllegalArgumentException("No cluster found for device " + connectPoint.deviceId()); 200 throw new IllegalArgumentException("No cluster found for device " + connectPoint.deviceId());
192 } 201 }
193 202
194 - // If the broadcast tree is null or empty, or if the point explicitly 203 + // If the broadcast set is null or empty, or if the point explicitly
195 - // belongs to the broadcast tree points, return true; 204 + // belongs to it, return true;
196 Set<ConnectPoint> points = broadcastSets.get(cluster.id()); 205 Set<ConnectPoint> points = broadcastSets.get(cluster.id());
197 return points == null || points.isEmpty() || points.contains(connectPoint); 206 return points == null || points.isEmpty() || points.contains(connectPoint);
198 } 207 }
199 208
200 /** 209 /**
210 + * Returns the size of the cluster broadcast set.
211 + *
212 + * @param clusterId cluster identifier
213 + * @return size of the cluster broadcast set
214 + */
215 + int broadcastSetSize(ClusterId clusterId) {
216 + return broadcastSets.get(clusterId).size();
217 + }
218 +
219 + /**
201 * Returns the set of pre-computed shortest paths between source and 220 * Returns the set of pre-computed shortest paths between source and
202 * destination devices. 221 * destination devices.
203 * 222 *
......
...@@ -144,7 +144,7 @@ class SimpleTopologyStore { ...@@ -144,7 +144,7 @@ class SimpleTopologyStore {
144 * @return true if broadcast allowed; false otherwise 144 * @return true if broadcast allowed; false otherwise
145 */ 145 */
146 boolean isBroadcastPoint(DefaultTopology topology, ConnectPoint connectPoint) { 146 boolean isBroadcastPoint(DefaultTopology topology, ConnectPoint connectPoint) {
147 - return topology.isInBroadcastTree(connectPoint); 147 + return topology.isBroadcastPoint(connectPoint);
148 } 148 }
149 149
150 /** 150 /**
......
1 /** 1 /**
2 - * Core subsystem for tracking consistent topology graph views. 2 + * Core subsystem for tracking global &amp; consistent topology graph views.
3 */ 3 */
4 package org.onlab.onos.net.trivial.topology.impl; 4 package org.onlab.onos.net.trivial.topology.impl;
......
1 +package org.onlab.onos.net.trivial.topology.impl;
2 +
3 +import org.junit.Before;
4 +import org.junit.Test;
5 +import org.onlab.onos.net.ConnectPoint;
6 +import org.onlab.onos.net.Device;
7 +import org.onlab.onos.net.DeviceId;
8 +import org.onlab.onos.net.Link;
9 +import org.onlab.onos.net.Path;
10 +import org.onlab.onos.net.PortNumber;
11 +import org.onlab.onos.net.provider.ProviderId;
12 +import org.onlab.onos.net.topology.ClusterId;
13 +import org.onlab.onos.net.topology.GraphDescription;
14 +import org.onlab.onos.net.topology.LinkWeight;
15 +import org.onlab.onos.net.topology.TopologyCluster;
16 +import org.onlab.onos.net.topology.TopologyEdge;
17 +
18 +import java.util.Set;
19 +
20 +import static com.google.common.collect.ImmutableSet.of;
21 +import static org.junit.Assert.*;
22 +import static org.onlab.onos.net.DeviceId.deviceId;
23 +import static org.onlab.onos.net.PortNumber.portNumber;
24 +import static org.onlab.onos.net.trivial.topology.impl.SimpleTopologyManagerTest.device;
25 +import static org.onlab.onos.net.trivial.topology.impl.SimpleTopologyManagerTest.link;
26 +
27 +/**
28 + * Test of the default topology implementation.
29 + */
30 +public class DefaultTopologyTest {
31 +
32 + public static final ProviderId PID = new ProviderId("foo.bar");
33 +
34 + public static final DeviceId D1 = deviceId("of:1");
35 + public static final DeviceId D2 = deviceId("of:2");
36 + public static final DeviceId D3 = deviceId("of:3");
37 + public static final DeviceId D4 = deviceId("of:4");
38 + public static final DeviceId D5 = deviceId("of:5");
39 +
40 + public static final PortNumber P1 = portNumber(1);
41 + public static final PortNumber P2 = portNumber(2);
42 +
43 + public static final LinkWeight WEIGHT = new LinkWeight() {
44 + @Override
45 + public double weight(TopologyEdge edge) {
46 + return edge.src().deviceId().equals(D4) ||
47 + edge.dst().deviceId().equals(D4) ? 2.0 : 1.0;
48 + }
49 + };
50 +
51 + private DefaultTopology dt;
52 +
53 + @Before
54 + public void setUp() {
55 + long now = System.currentTimeMillis();
56 + Set<Device> devices = of(device("1"), device("2"),
57 + device("3"), device("4"),
58 + device("5"));
59 + Set<Link> links = of(link("1", 1, "2", 1), link("2", 1, "1", 1),
60 + link("3", 2, "2", 2), link("2", 2, "3", 2),
61 + link("1", 3, "4", 3), link("4", 3, "1", 3),
62 + link("3", 4, "4", 4), link("4", 4, "3", 4));
63 + GraphDescription graphDescription =
64 + new DefaultGraphDescription(now, devices, links);
65 +
66 + dt = new DefaultTopology(PID, graphDescription);
67 + assertEquals("incorrect supplier", PID, dt.providerId());
68 + assertEquals("incorrect time", now, dt.time());
69 + assertEquals("incorrect device count", 5, dt.deviceCount());
70 + assertEquals("incorrect link count", 8, dt.linkCount());
71 + assertEquals("incorrect cluster count", 2, dt.clusterCount());
72 + assertEquals("incorrect broadcast set size", 6,
73 + dt.broadcastSetSize(ClusterId.clusterId(0)));
74 + }
75 +
76 + @Test
77 + public void pathRelated() {
78 + Set<Path> paths = dt.getPaths(D1, D2);
79 + assertEquals("incorrect path count", 1, paths.size());
80 +
81 + paths = dt.getPaths(D1, D3);
82 + assertEquals("incorrect path count", 2, paths.size());
83 +
84 + paths = dt.getPaths(D1, D5);
85 + assertTrue("no paths expected", paths.isEmpty());
86 +
87 + paths = dt.getPaths(D1, D3, WEIGHT);
88 + assertEquals("incorrect path count", 1, paths.size());
89 + }
90 +
91 + @Test
92 + public void pointRelated() {
93 + assertTrue("should be infrastructure point",
94 + dt.isInfrastructure(new ConnectPoint(D1, P1)));
95 + assertFalse("should not be infrastructure point",
96 + dt.isInfrastructure(new ConnectPoint(D1, P2)));
97 + }
98 +
99 + @Test
100 + public void clusterRelated() {
101 + Set<TopologyCluster> clusters = dt.getClusters();
102 + assertEquals("incorrect cluster count", 2, clusters.size());
103 +
104 + TopologyCluster c = dt.getCluster(D1);
105 + Set<DeviceId> devs = dt.getClusterDevices(c);
106 + assertEquals("incorrect cluster device count", 4, devs.size());
107 + assertTrue("cluster should contain D2", devs.contains(D2));
108 + assertFalse("cluster should not contain D5", devs.contains(D5));
109 + }
110 +
111 +}
...@@ -24,8 +24,6 @@ import org.projectfloodlight.openflow.types.*; ...@@ -24,8 +24,6 @@ import org.projectfloodlight.openflow.types.*;
24 import org.projectfloodlight.openflow.util.*; 24 import org.projectfloodlight.openflow.util.*;
25 import org.projectfloodlight.openflow.exceptions.*; 25 import org.projectfloodlight.openflow.exceptions.*;
26 import org.jboss.netty.buffer.ChannelBuffer; 26 import org.jboss.netty.buffer.ChannelBuffer;
27 -
28 -import java.nio.ByteBuffer;
29 import java.util.Set; 27 import java.util.Set;
30 28
31 abstract class OFActionBsnVer13 { 29 abstract class OFActionBsnVer13 {
...@@ -38,7 +36,7 @@ abstract class OFActionBsnVer13 { ...@@ -38,7 +36,7 @@ abstract class OFActionBsnVer13 {
38 36
39 static class Reader implements OFMessageReader<OFActionBsn> { 37 static class Reader implements OFMessageReader<OFActionBsn> {
40 @Override 38 @Override
41 - public OFActionBsn readFrom(ByteBuffer bb) throws OFParseError { 39 + public OFActionBsn readFrom(ChannelBuffer bb) throws OFParseError {
42 if(bb.readableBytes() < MINIMUM_LENGTH) 40 if(bb.readableBytes() < MINIMUM_LENGTH)
43 return null; 41 return null;
44 int start = bb.readerIndex(); 42 int start = bb.readerIndex();
......
...@@ -101,7 +101,6 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -101,7 +101,6 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
101 for (int i = 0; i < flowRules.length; i++) { 101 for (int i = 0; i < flowRules.length; i++) {
102 applyRule(flowRules[i]); 102 applyRule(flowRules[i]);
103 } 103 }
104 -
105 } 104 }
106 105
107 private void applyRule(FlowRule flowRule) { 106 private void applyRule(FlowRule flowRule) {
...@@ -120,9 +119,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr ...@@ -120,9 +119,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr
120 .setHardTimeout(10) 119 .setHardTimeout(10)
121 .setPriority(flowRule.priority()) 120 .setPriority(flowRule.priority())
122 .build(); 121 .build();
123 -
124 sw.sendMsg(fm); 122 sw.sendMsg(fm);
125 -
126 } 123 }
127 124
128 private List<OFAction> buildActions(List<Instruction> instructions, OFFactory factory) { 125 private List<OFAction> buildActions(List<Instruction> instructions, OFFactory factory) {
......
...@@ -12,7 +12,7 @@ export KARAF_LOG=$KARAF/data/log/karaf.log ...@@ -12,7 +12,7 @@ export KARAF_LOG=$KARAF/data/log/karaf.log
12 12
13 # Setup a path 13 # Setup a path
14 export PS=":" 14 export PS=":"
15 -export PATH="$PATH:$ONOS_ROOT/tools/dev;$ONOS_ROOT/tools/package" 15 +export PATH="$PATH:$ONOS_ROOT/tools/dev:$ONOS_ROOT/tools/package"
16 export PATH="$PATH:$MAVEN/bin:$KARAF/bin" 16 export PATH="$PATH:$MAVEN/bin:$KARAF/bin"
17 export PATH="$PATH:." 17 export PATH="$PATH:."
18 18
......
...@@ -29,18 +29,13 @@ cd $ONOS_STAGE ...@@ -29,18 +29,13 @@ cd $ONOS_STAGE
29 # Unroll the Apache Karaf bits and make the ONOS top-level directories. 29 # Unroll the Apache Karaf bits and make the ONOS top-level directories.
30 unzip $KARAF_ZIP 30 unzip $KARAF_ZIP
31 mkdir bin 31 mkdir bin
32 -mkdir lib
33 32
34 # Stage the ONOS admin scripts 33 # Stage the ONOS admin scripts
35 cp -r $ONOS_ROOT/tools/package/bin . 34 cp -r $ONOS_ROOT/tools/package/bin .
36 35
37 # Stage the ONOS bundles 36 # Stage the ONOS bundles
38 -mkdir -p lib/org/onlab 37 +mkdir -p system/org/onlab
39 -cp -r $M2_REPO/org/onlab lib/org 38 +cp -r $M2_REPO/org/onlab system/org/
40 -
41 -
42 -# Patch the Apache Karaf distribution file to point to the lib as maven repo
43 -#perl -pi.old -e "s|^org.ops4j.pax.url.mvn.repositories= |org.ops4j.pax.url.mvn.repositories= \\\n file:../../lib, |" $ONOS_STAGE/$KARAF_DIST/etc/org.ops4j.pax.url.mvn.cfg
44 39
45 # Patch the Apache Karaf distribution file to add ONOS features repository 40 # Patch the Apache Karaf distribution file to add ONOS features repository
46 perl -pi.old -e "s|^(featuresRepositories=.*)|\1,mvn:org.onlab.onos/onos-features/$ONOS_VERSION/xml/features|" \ 41 perl -pi.old -e "s|^(featuresRepositories=.*)|\1,mvn:org.onlab.onos/onos-features/$ONOS_VERSION/xml/features|" \
......
...@@ -5,7 +5,7 @@ import java.util.Arrays; ...@@ -5,7 +5,7 @@ import java.util.Arrays;
5 /** 5 /**
6 * A class representing an IPv4 address. 6 * A class representing an IPv4 address.
7 */ 7 */
8 -public class IpAddress { 8 +public final class IpAddress {
9 9
10 //IP Versions 10 //IP Versions
11 public enum Version { INET, INET6 }; 11 public enum Version { INET, INET6 };
...@@ -14,13 +14,30 @@ public class IpAddress { ...@@ -14,13 +14,30 @@ public class IpAddress {
14 public static final int INET_LEN = 4; 14 public static final int INET_LEN = 4;
15 public static final int INET6_LEN = 16; 15 public static final int INET6_LEN = 16;
16 16
17 + //maximum CIDR value
18 + public static final int MAX_INET_MASK = 32;
19 + public static final int DEFAULT_MASK = 0;
20 +
21 + /**
22 + * Default value indicating an unspecified address.
23 + */
24 + public static final byte [] ANY = new byte [] {0, 0, 0, 0};
25 +
17 protected Version version; 26 protected Version version;
18 - //does it make more sense to have a integral address? 27 +
19 protected byte[] octets; 28 protected byte[] octets;
29 + protected int netmask;
20 30
21 - protected IpAddress(Version ver, byte[] octets) { 31 + private IpAddress(Version ver, byte[] octets, int netmask) {
22 this.version = ver; 32 this.version = ver;
23 this.octets = Arrays.copyOf(octets, INET_LEN); 33 this.octets = Arrays.copyOf(octets, INET_LEN);
34 + this.netmask = netmask;
35 + }
36 +
37 + private IpAddress(Version ver, byte[] octets) {
38 + this.version = ver;
39 + this.octets = Arrays.copyOf(octets, INET_LEN);
40 + this.netmask = DEFAULT_MASK;
24 } 41 }
25 42
26 /** 43 /**
...@@ -34,38 +51,87 @@ public class IpAddress { ...@@ -34,38 +51,87 @@ public class IpAddress {
34 } 51 }
35 52
36 /** 53 /**
37 - * Converts an integer into an IPv4 address. 54 + * Converts a byte array into an IP address.
38 * 55 *
39 - * @param address an integer representing an IP value 56 + * @param address a byte array
57 + * @param netmask the CIDR value subnet mask
40 * @return an IP address 58 * @return an IP address
41 */ 59 */
42 - public static IpAddress valueOf(int address) { 60 + public static IpAddress valueOf(byte [] address, int netmask) {
61 + return new IpAddress(Version.INET, address, netmask);
62 + }
63 +
64 + /**
65 + * Helper to convert an integer into a byte array.
66 + *
67 + * @param address the integer to convert
68 + * @return a byte array
69 + */
70 + private static byte [] bytes(int address) {
43 byte [] bytes = new byte [INET_LEN]; 71 byte [] bytes = new byte [INET_LEN];
44 for (int i = 0; i < INET_LEN; i++) { 72 for (int i = 0; i < INET_LEN; i++) {
45 bytes[i] = (byte) ((address >> (INET_LEN - (i + 1)) * 8) & 0xff); 73 bytes[i] = (byte) ((address >> (INET_LEN - (i + 1)) * 8) & 0xff);
46 } 74 }
47 75
48 - return new IpAddress(Version.INET, bytes); 76 + return bytes;
77 + }
78 +
79 + /**
80 + * Converts an integer into an IPv4 address.
81 + *
82 + * @param address an integer representing an IP value
83 + * @return an IP address
84 + */
85 + public static IpAddress valueOf(int address) {
86 + return new IpAddress(Version.INET, bytes(address));
87 + }
88 +
89 + /**
90 + * Converts an integer into an IPv4 address.
91 + *
92 + * @param address an integer representing an IP value
93 + * @param netmask the CIDR value subnet mask
94 + * @return an IP address
95 + */
96 + public static IpAddress valueOf(int address, int netmask) {
97 + return new IpAddress(Version.INET, bytes(address), netmask);
49 } 98 }
50 99
51 /** 100 /**
52 - * Converts a string in dotted-decimal notation (x.x.x.x) into 101 + * Converts a dotted-decimal string (x.x.x.x) into an IPv4 address. The
53 - * an IPv4 address. 102 + * string can also be in CIDR (slash) notation.
54 * 103 *
55 - * @param address a string representing an IP address, e.g. "10.0.0.1" 104 + * @param address a IP address in string form, e.g. "10.0.0.1", "10.0.0.1/24"
56 * @return an IP address 105 * @return an IP address
57 */ 106 */
58 public static IpAddress valueOf(String address) { 107 public static IpAddress valueOf(String address) {
59 - final String [] parts = address.split("\\."); 108 +
60 - if (parts.length != INET_LEN) { 109 + final String [] parts = address.split("\\/");
110 + if (parts.length > 2) {
111 + throw new IllegalArgumentException("Malformed IP address string; "
112 + + "Addres must take form \"x.x.x.x\" or \"x.x.x.x/y\"");
113 + }
114 +
115 + int mask = DEFAULT_MASK;
116 + if (parts.length == 2) {
117 + mask = Integer.valueOf(parts[1]);
118 + if (mask > MAX_INET_MASK) {
119 + throw new IllegalArgumentException(
120 + "Value of subnet mask cannot exceed "
121 + + MAX_INET_MASK);
122 + }
123 + }
124 +
125 + final String [] net = parts[0].split("\\.");
126 + if (net.length != INET_LEN) {
61 throw new IllegalArgumentException("Malformed IP address string; " 127 throw new IllegalArgumentException("Malformed IP address string; "
62 + "Addres must have four decimal values separated by dots (.)"); 128 + "Addres must have four decimal values separated by dots (.)");
63 } 129 }
64 final byte [] bytes = new byte[INET_LEN]; 130 final byte [] bytes = new byte[INET_LEN];
65 for (int i = 0; i < INET_LEN; i++) { 131 for (int i = 0; i < INET_LEN; i++) {
66 - bytes[i] = Byte.parseByte(parts[i], 10); 132 + bytes[i] = (byte) Short.parseShort(net[i], 10);
67 } 133 }
68 - return new IpAddress(Version.INET, bytes); 134 + return new IpAddress(Version.INET, bytes, mask);
69 } 135 }
70 136
71 /** 137 /**
...@@ -99,34 +165,122 @@ public class IpAddress { ...@@ -99,34 +165,122 @@ public class IpAddress {
99 return address; 165 return address;
100 } 166 }
101 167
102 - @Override 168 + /**
103 - public String toString() { 169 + * Helper for computing the mask value from CIDR.
104 - final StringBuilder builder = new StringBuilder(); 170 + *
105 - for (final byte b : this.octets) { 171 + * @return an integer bitmask
106 - if (builder.length() > 0) { 172 + */
107 - builder.append("."); 173 + private int mask() {
174 + int shift = MAX_INET_MASK - this.netmask;
175 + return ((Integer.MAX_VALUE >>> (shift - 1)) << shift);
108 } 176 }
109 - builder.append(String.format("%d", b)); 177 +
178 + /**
179 + * Returns the subnet mask in IpAddress form. The netmask value for
180 + * the returned IpAddress is 0, as the address itself is a mask.
181 + *
182 + * @return the subnet mask
183 + */
184 + public IpAddress netmask() {
185 + return new IpAddress(Version.INET, bytes(mask()));
110 } 186 }
111 - return builder.toString(); 187 +
188 + /**
189 + * Returns the network portion of this address as an IpAddress.
190 + * The netmask of the returned IpAddress is the current mask. If this
191 + * address doesn't have a mask, this returns an all-0 IpAddress.
192 + *
193 + * @return the network address or null
194 + */
195 + public IpAddress network() {
196 + if (netmask == DEFAULT_MASK) {
197 + return new IpAddress(version, ANY, DEFAULT_MASK);
198 + }
199 +
200 + byte [] net = new byte [4];
201 + byte [] mask = bytes(mask());
202 + for (int i = 0; i < INET_LEN; i++) {
203 + net[i] = (byte) (octets[i] & mask[i]);
204 + }
205 + return new IpAddress(version, net, netmask);
206 + }
207 +
208 + /**
209 + * Returns the host portion of the IPAddress, as an IPAddress.
210 + * The netmask of the returned IpAddress is the current mask. If this
211 + * address doesn't have a mask, this returns a copy of the current
212 + * address.
213 + *
214 + * @return the host address
215 + */
216 + public IpAddress host() {
217 + if (netmask == DEFAULT_MASK) {
218 + new IpAddress(version, octets, netmask);
219 + }
220 +
221 + byte [] host = new byte [INET_LEN];
222 + byte [] mask = bytes(mask());
223 + for (int i = 0; i < INET_LEN; i++) {
224 + host[i] = (byte) (octets[i] & ~mask[i]);
225 + }
226 + return new IpAddress(version, host, netmask);
112 } 227 }
113 228
114 @Override 229 @Override
115 public int hashCode() { 230 public int hashCode() {
116 - return Arrays.hashCode(octets); 231 + final int prime = 31;
232 + int result = 1;
233 + result = prime * result + netmask;
234 + result = prime * result + Arrays.hashCode(octets);
235 + result = prime * result + ((version == null) ? 0 : version.hashCode());
236 + return result;
117 } 237 }
118 238
119 @Override 239 @Override
120 public boolean equals(Object obj) { 240 public boolean equals(Object obj) {
121 - 241 + if (this == obj) {
122 - if (obj instanceof IpAddress) {
123 - IpAddress other = (IpAddress) obj;
124 -
125 - if (this.version.equals(other.version)
126 - && (Arrays.equals(this.octets, other.octets))) {
127 return true; 242 return true;
128 } 243 }
244 + if (obj == null) {
245 + return false;
246 + }
247 + if (getClass() != obj.getClass()) {
248 + return false;
129 } 249 }
250 + IpAddress other = (IpAddress) obj;
251 + if (netmask != other.netmask) {
130 return false; 252 return false;
131 } 253 }
254 + if (!Arrays.equals(octets, other.octets)) {
255 + return false;
256 + }
257 + if (version != other.version) {
258 + return false;
259 + }
260 + return true;
261 + }
262 +
263 + @Override
264 + /*
265 + * (non-Javadoc)
266 + * format is "x.x.x.x" for non-masked (netmask 0) addresses,
267 + * and "x.x.x.x/y" for masked addresses.
268 + *
269 + * @see java.lang.Object#toString()
270 + */
271 + public String toString() {
272 + final StringBuilder builder = new StringBuilder();
273 + for (final byte b : this.octets) {
274 + if (builder.length() > 0) {
275 + builder.append(".");
276 + }
277 + builder.append(String.format("%d", b & 0xff));
278 + }
279 + if (netmask != DEFAULT_MASK) {
280 + builder.append("/");
281 + builder.append(String.format("%d", netmask));
282 + }
283 + return builder.toString();
284 + }
285 +
132 } 286 }
......
1 package org.onlab.packet; 1 package org.onlab.packet;
2 2
3 import static org.junit.Assert.assertEquals; 3 import static org.junit.Assert.assertEquals;
4 +import static org.junit.Assert.assertTrue;
4 5
5 import java.util.Arrays; 6 import java.util.Arrays;
6 7
...@@ -11,33 +12,65 @@ import com.google.common.testing.EqualsTester; ...@@ -11,33 +12,65 @@ import com.google.common.testing.EqualsTester;
11 12
12 public class IPAddressTest { 13 public class IPAddressTest {
13 14
14 - private static final byte [] BYTES1 = new byte [] {0x0, 0x0, 0x0, 0xa}; 15 + private static final byte [] BYTES1 = new byte [] {0xa, 0x0, 0x0, 0xa};
15 - private static final byte [] BYTES2 = new byte [] {0x0, 0x0, 0x0, 0xb}; 16 + private static final byte [] BYTES2 = new byte [] {0xa, 0x0, 0x0, 0xb};
16 - private static final int INTVAL1 = 10; 17 + private static final int INTVAL1 = 167772170;
17 - private static final int INTVAL2 = 12; 18 + private static final int INTVAL2 = 167772171;
18 - private static final String STRVAL = "0.0.0.11"; 19 + private static final String STRVAL = "10.0.0.12";
20 + private static final int MASK = 16;
19 21
20 @Test 22 @Test
21 public void testEquality() { 23 public void testEquality() {
22 IpAddress ip1 = IpAddress.valueOf(BYTES1); 24 IpAddress ip1 = IpAddress.valueOf(BYTES1);
23 - IpAddress ip2 = IpAddress.valueOf(BYTES2); 25 + IpAddress ip2 = IpAddress.valueOf(INTVAL1);
24 - IpAddress ip3 = IpAddress.valueOf(INTVAL1); 26 + IpAddress ip3 = IpAddress.valueOf(BYTES2);
25 IpAddress ip4 = IpAddress.valueOf(INTVAL2); 27 IpAddress ip4 = IpAddress.valueOf(INTVAL2);
26 IpAddress ip5 = IpAddress.valueOf(STRVAL); 28 IpAddress ip5 = IpAddress.valueOf(STRVAL);
27 29
28 - new EqualsTester().addEqualityGroup(ip1, ip3) 30 + new EqualsTester().addEqualityGroup(ip1, ip2)
29 - .addEqualityGroup(ip2, ip5) 31 + .addEqualityGroup(ip3, ip4)
30 - .addEqualityGroup(ip4) 32 + .addEqualityGroup(ip5)
31 .testEquals(); 33 .testEquals();
34 +
35 + // string conversions
36 + IpAddress ip6 = IpAddress.valueOf(BYTES1, MASK);
37 + IpAddress ip7 = IpAddress.valueOf("10.0.0.10/16");
38 + IpAddress ip8 = IpAddress.valueOf(new byte [] {0xa, 0x0, 0x0, 0xc});
39 + assertEquals("incorrect address conversion", ip6, ip7);
40 + assertEquals("incorrect address conversion", ip5, ip8);
32 } 41 }
33 42
34 @Test 43 @Test
35 public void basics() { 44 public void basics() {
36 - IpAddress ip4 = IpAddress.valueOf(BYTES1); 45 + IpAddress ip1 = IpAddress.valueOf(BYTES1, MASK);
37 - assertEquals("incorrect IP Version", Version.INET, ip4.version()); 46 + final byte [] bytes = new byte [] {0xa, 0x0, 0x0, 0xa};
38 - assertEquals("faulty toOctets()", Arrays.equals( 47 +
39 - new byte [] {0x0, 0x0, 0x0, 0xa}, ip4.toOctets()), true); 48 + //check fields
40 - assertEquals("faulty toInt()", INTVAL1, ip4.toInt()); 49 + assertEquals("incorrect IP Version", Version.INET, ip1.version());
41 - assertEquals("faulty toString()", "0.0.0.10", ip4.toString()); 50 + assertEquals("incorrect netmask", 16, ip1.netmask);
51 + assertTrue("faulty toOctets()", Arrays.equals(bytes, ip1.toOctets()));
52 + assertEquals("faulty toInt()", INTVAL1, ip1.toInt());
53 + assertEquals("faulty toString()", "10.0.0.10/16", ip1.toString());
54 + }
55 +
56 + @Test
57 + public void netmasks() {
58 + // masked
59 + IpAddress ip1 = IpAddress.valueOf(BYTES1, MASK);
60 +
61 + IpAddress host = IpAddress.valueOf("0.0.0.10/16");
62 + IpAddress network = IpAddress.valueOf("10.0.0.0/16");
63 + assertEquals("incorrect host address", host, ip1.host());
64 + assertEquals("incorrect network address", network, ip1.network());
65 + assertEquals("incorrect netmask", "255.255.0.0", ip1.netmask().toString());
66 +
67 + //unmasked
68 + IpAddress ip2 = IpAddress.valueOf(BYTES1);
69 + IpAddress umhost = IpAddress.valueOf("10.0.0.10/0");
70 + IpAddress umnet = IpAddress.valueOf("0.0.0.0/0");
71 + assertEquals("incorrect host address", umhost, ip2.host());
72 + assertEquals("incorrect host address", umnet, ip2.network());
73 + assertTrue("incorrect netmask",
74 + Arrays.equals(IpAddress.ANY, ip2.netmask().toOctets()));
42 } 75 }
43 } 76 }
......