Praseed Balakrishnan

Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next

Showing 31 changed files with 1718 additions and 93 deletions
...@@ -45,6 +45,12 @@ ...@@ -45,6 +45,12 @@
45 45
46 <dependency> 46 <dependency>
47 <groupId>org.onlab.onos</groupId> 47 <groupId>org.onlab.onos</groupId>
48 + <artifactId>onlab-junit</artifactId>
49 + <scope>test</scope>
50 + </dependency>
51 +
52 + <dependency>
53 + <groupId>org.onlab.onos</groupId>
48 <artifactId>onos-cli</artifactId> 54 <artifactId>onos-cli</artifactId>
49 <version>${project.version}</version> 55 <version>${project.version}</version>
50 </dependency> 56 </dependency>
......
1 package org.onlab.onos.sdnip; 1 package org.onlab.onos.sdnip;
2 2
3 +import java.util.List;
4 +
3 import org.onlab.onos.ApplicationId; 5 import org.onlab.onos.ApplicationId;
4 import org.onlab.onos.net.ConnectPoint; 6 import org.onlab.onos.net.ConnectPoint;
5 import org.onlab.onos.net.flow.DefaultTrafficSelector; 7 import org.onlab.onos.net.flow.DefaultTrafficSelector;
...@@ -8,6 +10,7 @@ import org.onlab.onos.net.flow.TrafficSelector; ...@@ -8,6 +10,7 @@ import org.onlab.onos.net.flow.TrafficSelector;
8 import org.onlab.onos.net.flow.TrafficTreatment; 10 import org.onlab.onos.net.flow.TrafficTreatment;
9 import org.onlab.onos.net.intent.IntentService; 11 import org.onlab.onos.net.intent.IntentService;
10 import org.onlab.onos.net.intent.PointToPointIntent; 12 import org.onlab.onos.net.intent.PointToPointIntent;
13 +import org.onlab.onos.sdnip.bgp.BgpConstants;
11 import org.onlab.onos.sdnip.config.BgpPeer; 14 import org.onlab.onos.sdnip.config.BgpPeer;
12 import org.onlab.onos.sdnip.config.BgpSpeaker; 15 import org.onlab.onos.sdnip.config.BgpSpeaker;
13 import org.onlab.onos.sdnip.config.Interface; 16 import org.onlab.onos.sdnip.config.Interface;
...@@ -20,8 +23,6 @@ import org.onlab.packet.IpPrefix; ...@@ -20,8 +23,6 @@ import org.onlab.packet.IpPrefix;
20 import org.slf4j.Logger; 23 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory; 24 import org.slf4j.LoggerFactory;
22 25
23 -import java.util.List;
24 -
25 /** 26 /**
26 * Manages the connectivity requirements between peers. 27 * Manages the connectivity requirements between peers.
27 */ 28 */
...@@ -30,37 +31,44 @@ public class PeerConnectivityManager { ...@@ -30,37 +31,44 @@ public class PeerConnectivityManager {
30 private static final Logger log = LoggerFactory.getLogger( 31 private static final Logger log = LoggerFactory.getLogger(
31 PeerConnectivityManager.class); 32 PeerConnectivityManager.class);
32 33
33 - // TODO these shouldn't be defined here 34 + private final SdnIpConfigService configService;
34 - private static final short BGP_PORT = 179;
35 - private static final int IPV4_BIT_LENGTH = 32;
36 -
37 - private final SdnIpConfigService configInfoService;
38 private final InterfaceService interfaceService; 35 private final InterfaceService interfaceService;
39 private final IntentService intentService; 36 private final IntentService intentService;
40 37
41 private final ApplicationId appId; 38 private final ApplicationId appId;
42 39
40 + /**
41 + * Creates a new PeerConnectivityManager.
42 + *
43 + * @param appId the application ID
44 + * @param configService the SDN-IP config service
45 + * @param interfaceService the interface service
46 + * @param intentService the intent service
47 + */
43 public PeerConnectivityManager(ApplicationId appId, 48 public PeerConnectivityManager(ApplicationId appId,
44 - SdnIpConfigService configInfoService, 49 + SdnIpConfigService configService,
45 InterfaceService interfaceService, 50 InterfaceService interfaceService,
46 IntentService intentService) { 51 IntentService intentService) {
47 this.appId = appId; 52 this.appId = appId;
48 - this.configInfoService = configInfoService; 53 + this.configService = configService;
49 this.interfaceService = interfaceService; 54 this.interfaceService = interfaceService;
50 this.intentService = intentService; 55 this.intentService = intentService;
51 } 56 }
52 57
58 + /**
59 + * Starts the peer connectivity manager.
60 + */
53 public void start() { 61 public void start() {
54 // TODO are any of these errors? 62 // TODO are any of these errors?
55 if (interfaceService.getInterfaces().isEmpty()) { 63 if (interfaceService.getInterfaces().isEmpty()) {
56 64
57 log.warn("The interface in configuration file is empty. " 65 log.warn("The interface in configuration file is empty. "
58 + "Thus, the SDN-IP application can not be started."); 66 + "Thus, the SDN-IP application can not be started.");
59 - } else if (configInfoService.getBgpPeers().isEmpty()) { 67 + } else if (configService.getBgpPeers().isEmpty()) {
60 68
61 log.warn("The BGP peer in configuration file is empty." 69 log.warn("The BGP peer in configuration file is empty."
62 + "Thus, the SDN-IP application can not be started."); 70 + "Thus, the SDN-IP application can not be started.");
63 - } else if (configInfoService.getBgpSpeakers() == null) { 71 + } else if (configService.getBgpSpeakers() == null) {
64 72
65 log.error("The BGP speaker in configuration file is empty. " 73 log.error("The BGP speaker in configuration file is empty. "
66 + "Thus, the SDN-IP application can not be started."); 74 + "Thus, the SDN-IP application can not be started.");
...@@ -79,7 +87,7 @@ public class PeerConnectivityManager { ...@@ -79,7 +87,7 @@ public class PeerConnectivityManager {
79 * for paths from all peers to each BGP speaker. 87 * for paths from all peers to each BGP speaker.
80 */ 88 */
81 private void setupBgpPaths() { 89 private void setupBgpPaths() {
82 - for (BgpSpeaker bgpSpeaker : configInfoService.getBgpSpeakers() 90 + for (BgpSpeaker bgpSpeaker : configService.getBgpSpeakers()
83 .values()) { 91 .values()) {
84 log.debug("Start to set up BGP paths for BGP speaker: {}", 92 log.debug("Start to set up BGP paths for BGP speaker: {}",
85 bgpSpeaker); 93 bgpSpeaker);
...@@ -88,7 +96,7 @@ public class PeerConnectivityManager { ...@@ -88,7 +96,7 @@ public class PeerConnectivityManager {
88 List<InterfaceAddress> interfaceAddresses = 96 List<InterfaceAddress> interfaceAddresses =
89 bgpSpeaker.interfaceAddresses(); 97 bgpSpeaker.interfaceAddresses();
90 98
91 - for (BgpPeer bgpPeer : configInfoService.getBgpPeers().values()) { 99 + for (BgpPeer bgpPeer : configService.getBgpPeers().values()) {
92 100
93 log.debug("Start to set up BGP paths between BGP speaker: {} " 101 log.debug("Start to set up BGP paths between BGP speaker: {} "
94 + "to BGP peer: {}", bgpSpeaker, bgpPeer); 102 + "to BGP peer: {}", bgpSpeaker, bgpPeer);
...@@ -121,16 +129,14 @@ public class PeerConnectivityManager { ...@@ -121,16 +129,14 @@ public class PeerConnectivityManager {
121 129
122 // install intent for BGP path from BGPd to BGP peer matching 130 // install intent for BGP path from BGPd to BGP peer matching
123 // destination TCP port 179 131 // destination TCP port 179
124 -
125 - // TODO: The usage of PacketMatchBuilder will be improved, then we
126 - // only need to new the PacketMatchBuilder once.
127 - // By then, the code here will be improved accordingly.
128 TrafficSelector selector = DefaultTrafficSelector.builder() 132 TrafficSelector selector = DefaultTrafficSelector.builder()
129 .matchEthType(Ethernet.TYPE_IPV4) 133 .matchEthType(Ethernet.TYPE_IPV4)
130 .matchIPProtocol(IPv4.PROTOCOL_TCP) 134 .matchIPProtocol(IPv4.PROTOCOL_TCP)
131 - .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH)) 135 + .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(),
132 - .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH)) 136 + IpAddress.MAX_INET_MASK))
133 - .matchTcpDst(BGP_PORT) 137 + .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
138 + IpAddress.MAX_INET_MASK))
139 + .matchTcpDst((short) BgpConstants.BGP_PORT)
134 .build(); 140 .build();
135 141
136 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 142 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
...@@ -149,9 +155,11 @@ public class PeerConnectivityManager { ...@@ -149,9 +155,11 @@ public class PeerConnectivityManager {
149 selector = DefaultTrafficSelector.builder() 155 selector = DefaultTrafficSelector.builder()
150 .matchEthType(Ethernet.TYPE_IPV4) 156 .matchEthType(Ethernet.TYPE_IPV4)
151 .matchIPProtocol(IPv4.PROTOCOL_TCP) 157 .matchIPProtocol(IPv4.PROTOCOL_TCP)
152 - .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH)) 158 + .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(),
153 - .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH)) 159 + IpAddress.MAX_INET_MASK))
154 - .matchTcpSrc(BGP_PORT) 160 + .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
161 + IpAddress.MAX_INET_MASK))
162 + .matchTcpSrc((short) BgpConstants.BGP_PORT)
155 .build(); 163 .build();
156 164
157 PointToPointIntent intentMatchSrcTcpPort = 165 PointToPointIntent intentMatchSrcTcpPort =
...@@ -167,9 +175,11 @@ public class PeerConnectivityManager { ...@@ -167,9 +175,11 @@ public class PeerConnectivityManager {
167 selector = DefaultTrafficSelector.builder() 175 selector = DefaultTrafficSelector.builder()
168 .matchEthType(Ethernet.TYPE_IPV4) 176 .matchEthType(Ethernet.TYPE_IPV4)
169 .matchIPProtocol(IPv4.PROTOCOL_TCP) 177 .matchIPProtocol(IPv4.PROTOCOL_TCP)
170 - .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH)) 178 + .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
171 - .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH)) 179 + IpAddress.MAX_INET_MASK))
172 - .matchTcpDst(BGP_PORT) 180 + .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(),
181 + IpAddress.MAX_INET_MASK))
182 + .matchTcpDst((short) BgpConstants.BGP_PORT)
173 .build(); 183 .build();
174 184
175 PointToPointIntent reversedIntentMatchDstTcpPort = 185 PointToPointIntent reversedIntentMatchDstTcpPort =
...@@ -185,9 +195,11 @@ public class PeerConnectivityManager { ...@@ -185,9 +195,11 @@ public class PeerConnectivityManager {
185 selector = DefaultTrafficSelector.builder() 195 selector = DefaultTrafficSelector.builder()
186 .matchEthType(Ethernet.TYPE_IPV4) 196 .matchEthType(Ethernet.TYPE_IPV4)
187 .matchIPProtocol(IPv4.PROTOCOL_TCP) 197 .matchIPProtocol(IPv4.PROTOCOL_TCP)
188 - .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH)) 198 + .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
189 - .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH)) 199 + IpAddress.MAX_INET_MASK))
190 - .matchTcpSrc(BGP_PORT) 200 + .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(),
201 + IpAddress.MAX_INET_MASK))
202 + .matchTcpSrc((short) BgpConstants.BGP_PORT)
191 .build(); 203 .build();
192 204
193 PointToPointIntent reversedIntentMatchSrcTcpPort = 205 PointToPointIntent reversedIntentMatchSrcTcpPort =
...@@ -211,7 +223,7 @@ public class PeerConnectivityManager { ...@@ -211,7 +223,7 @@ public class PeerConnectivityManager {
211 * for paths from all peers to each BGP speaker. 223 * for paths from all peers to each BGP speaker.
212 */ 224 */
213 private void setupIcmpPaths() { 225 private void setupIcmpPaths() {
214 - for (BgpSpeaker bgpSpeaker : configInfoService.getBgpSpeakers() 226 + for (BgpSpeaker bgpSpeaker : configService.getBgpSpeakers()
215 .values()) { 227 .values()) {
216 log.debug("Start to set up ICMP paths for BGP speaker: {}", 228 log.debug("Start to set up ICMP paths for BGP speaker: {}",
217 bgpSpeaker); 229 bgpSpeaker);
...@@ -219,7 +231,7 @@ public class PeerConnectivityManager { ...@@ -219,7 +231,7 @@ public class PeerConnectivityManager {
219 List<InterfaceAddress> interfaceAddresses = bgpSpeaker 231 List<InterfaceAddress> interfaceAddresses = bgpSpeaker
220 .interfaceAddresses(); 232 .interfaceAddresses();
221 233
222 - for (BgpPeer bgpPeer : configInfoService.getBgpPeers().values()) { 234 + for (BgpPeer bgpPeer : configService.getBgpPeers().values()) {
223 235
224 Interface peerInterface = interfaceService.getInterface( 236 Interface peerInterface = interfaceService.getInterface(
225 bgpPeer.connectPoint()); 237 bgpPeer.connectPoint());
...@@ -253,8 +265,10 @@ public class PeerConnectivityManager { ...@@ -253,8 +265,10 @@ public class PeerConnectivityManager {
253 TrafficSelector selector = DefaultTrafficSelector.builder() 265 TrafficSelector selector = DefaultTrafficSelector.builder()
254 .matchEthType(Ethernet.TYPE_IPV4) 266 .matchEthType(Ethernet.TYPE_IPV4)
255 .matchIPProtocol(IPv4.PROTOCOL_ICMP) 267 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
256 - .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH)) 268 + .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(),
257 - .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH)) 269 + IpAddress.MAX_INET_MASK))
270 + .matchIPDst(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
271 + IpAddress.MAX_INET_MASK))
258 .build(); 272 .build();
259 273
260 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 274 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
...@@ -271,8 +285,10 @@ public class PeerConnectivityManager { ...@@ -271,8 +285,10 @@ public class PeerConnectivityManager {
271 selector = DefaultTrafficSelector.builder() 285 selector = DefaultTrafficSelector.builder()
272 .matchEthType(Ethernet.TYPE_IPV4) 286 .matchEthType(Ethernet.TYPE_IPV4)
273 .matchIPProtocol(IPv4.PROTOCOL_ICMP) 287 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
274 - .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(), IPV4_BIT_LENGTH)) 288 + .matchIPSrc(IpPrefix.valueOf(bgpdPeerAddress.toInt(),
275 - .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH)) 289 + IpAddress.MAX_INET_MASK))
290 + .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(),
291 + IpAddress.MAX_INET_MASK))
276 .build(); 292 .build();
277 293
278 PointToPointIntent reversedIntent = 294 PointToPointIntent reversedIntent =
......
...@@ -55,8 +55,6 @@ import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree; ...@@ -55,8 +55,6 @@ import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
55 /** 55 /**
56 * This class processes BGP route update, translates each update into a intent 56 * This class processes BGP route update, translates each update into a intent
57 * and submits the intent. 57 * and submits the intent.
58 - * <p/>
59 - * TODO: Make it thread-safe.
60 */ 58 */
61 public class Router implements RouteListener { 59 public class Router implements RouteListener {
62 60
...@@ -69,14 +67,13 @@ public class Router implements RouteListener { ...@@ -69,14 +67,13 @@ public class Router implements RouteListener {
69 // Stores all incoming route updates in a queue. 67 // Stores all incoming route updates in a queue.
70 private BlockingQueue<RouteUpdate> routeUpdates; 68 private BlockingQueue<RouteUpdate> routeUpdates;
71 69
72 - // The Ip4Address is the next hop address of each route update. 70 + // The IpAddress is the next hop address of each route update.
73 private SetMultimap<IpAddress, RouteEntry> routesWaitingOnArp; 71 private SetMultimap<IpAddress, RouteEntry> routesWaitingOnArp;
74 private ConcurrentHashMap<IpPrefix, MultiPointToSinglePointIntent> pushedRouteIntents; 72 private ConcurrentHashMap<IpPrefix, MultiPointToSinglePointIntent> pushedRouteIntents;
75 73
76 private IntentService intentService; 74 private IntentService intentService;
77 - //private IProxyArpService proxyArp;
78 private HostService hostService; 75 private HostService hostService;
79 - private SdnIpConfigService configInfoService; 76 + private SdnIpConfigService configService;
80 private InterfaceService interfaceService; 77 private InterfaceService interfaceService;
81 78
82 private ExecutorService bgpUpdatesExecutor; 79 private ExecutorService bgpUpdatesExecutor;
...@@ -98,18 +95,19 @@ public class Router implements RouteListener { ...@@ -98,18 +95,19 @@ public class Router implements RouteListener {
98 /** 95 /**
99 * Class constructor. 96 * Class constructor.
100 * 97 *
98 + * @param appId the application ID
101 * @param intentService the intent service 99 * @param intentService the intent service
102 * @param hostService the host service 100 * @param hostService the host service
103 - * @param configInfoService the configuration service 101 + * @param configService the configuration service
104 * @param interfaceService the interface service 102 * @param interfaceService the interface service
105 */ 103 */
106 public Router(ApplicationId appId, IntentService intentService, 104 public Router(ApplicationId appId, IntentService intentService,
107 - HostService hostService, SdnIpConfigService configInfoService, 105 + HostService hostService, SdnIpConfigService configService,
108 InterfaceService interfaceService) { 106 InterfaceService interfaceService) {
109 this.appId = appId; 107 this.appId = appId;
110 this.intentService = intentService; 108 this.intentService = intentService;
111 this.hostService = hostService; 109 this.hostService = hostService;
112 - this.configInfoService = configInfoService; 110 + this.configService = configService;
113 this.interfaceService = interfaceService; 111 this.interfaceService = interfaceService;
114 112
115 bgpRoutes = new ConcurrentInvertedRadixTree<>( 113 bgpRoutes = new ConcurrentInvertedRadixTree<>(
...@@ -172,7 +170,7 @@ public class Router implements RouteListener { ...@@ -172,7 +170,7 @@ public class Router implements RouteListener {
172 170
173 @Override 171 @Override
174 public void update(RouteUpdate routeUpdate) { 172 public void update(RouteUpdate routeUpdate) {
175 - log.debug("Received new route Update: {}", routeUpdate); 173 + log.debug("Received new route update: {}", routeUpdate);
176 174
177 try { 175 try {
178 routeUpdates.put(routeUpdate); 176 routeUpdates.put(routeUpdate);
...@@ -498,9 +496,11 @@ public class Router implements RouteListener { ...@@ -498,9 +496,11 @@ public class Router implements RouteListener {
498 private void executeRouteAdd(RouteEntry routeEntry) { 496 private void executeRouteAdd(RouteEntry routeEntry) {
499 log.debug("Executing route add: {}", routeEntry); 497 log.debug("Executing route add: {}", routeEntry);
500 498
499 + // Monitor the IP address so we'll get notified of updates to the MAC
500 + // address.
501 + hostService.startMonitoringIp(routeEntry.nextHop());
502 +
501 // See if we know the MAC address of the next hop 503 // See if we know the MAC address of the next hop
502 - //MacAddress nextHopMacAddress =
503 - //proxyArp.getMacAddress(routeEntry.getNextHop());
504 MacAddress nextHopMacAddress = null; 504 MacAddress nextHopMacAddress = null;
505 Set<Host> hosts = hostService.getHostsByIp( 505 Set<Host> hosts = hostService.getHostsByIp(
506 routeEntry.nextHop().toPrefix()); 506 routeEntry.nextHop().toPrefix());
...@@ -511,9 +511,6 @@ public class Router implements RouteListener { ...@@ -511,9 +511,6 @@ public class Router implements RouteListener {
511 511
512 if (nextHopMacAddress == null) { 512 if (nextHopMacAddress == null) {
513 routesWaitingOnArp.put(routeEntry.nextHop(), routeEntry); 513 routesWaitingOnArp.put(routeEntry.nextHop(), routeEntry);
514 - //proxyArp.sendArpRequest(routeEntry.getNextHop(), this, true);
515 - // TODO maybe just do this for every prefix anyway
516 - hostService.startMonitoringIp(routeEntry.nextHop());
517 return; 514 return;
518 } 515 }
519 516
...@@ -536,11 +533,11 @@ public class Router implements RouteListener { ...@@ -536,11 +533,11 @@ public class Router implements RouteListener {
536 533
537 // Find the attachment point (egress interface) of the next hop 534 // Find the attachment point (egress interface) of the next hop
538 Interface egressInterface; 535 Interface egressInterface;
539 - if (configInfoService.getBgpPeers().containsKey(nextHopIpAddress)) { 536 + if (configService.getBgpPeers().containsKey(nextHopIpAddress)) {
540 // Route to a peer 537 // Route to a peer
541 log.debug("Route to peer {}", nextHopIpAddress); 538 log.debug("Route to peer {}", nextHopIpAddress);
542 BgpPeer peer = 539 BgpPeer peer =
543 - configInfoService.getBgpPeers().get(nextHopIpAddress); 540 + configService.getBgpPeers().get(nextHopIpAddress);
544 egressInterface = 541 egressInterface =
545 interfaceService.getInterface(peer.connectPoint()); 542 interfaceService.getInterface(peer.connectPoint());
546 } else { 543 } else {
...@@ -593,17 +590,12 @@ public class Router implements RouteListener { ...@@ -593,17 +590,12 @@ public class Router implements RouteListener {
593 } 590 }
594 591
595 // Match the destination IP prefix at the first hop 592 // Match the destination IP prefix at the first hop
596 - //PacketMatchBuilder builder = new PacketMatchBuilder();
597 - //builder.setEtherType(Ethernet.TYPE_IPV4).setDstIpNet(prefix);
598 - //PacketMatch packetMatch = builder.build();
599 TrafficSelector selector = DefaultTrafficSelector.builder() 593 TrafficSelector selector = DefaultTrafficSelector.builder()
600 .matchEthType(Ethernet.TYPE_IPV4) 594 .matchEthType(Ethernet.TYPE_IPV4)
601 .matchIPDst(prefix) 595 .matchIPDst(prefix)
602 .build(); 596 .build();
603 597
604 // Rewrite the destination MAC address 598 // Rewrite the destination MAC address
605 - //ModifyDstMacAction modifyDstMacAction =
606 - //new ModifyDstMacAction(nextHopMacAddress);
607 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 599 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
608 .setEthDst(nextHopMacAddress) 600 .setEthDst(nextHopMacAddress)
609 .build(); 601 .build();
...@@ -635,10 +627,6 @@ public class Router implements RouteListener { ...@@ -635,10 +627,6 @@ public class Router implements RouteListener {
635 log.debug("Processing route delete: {}", routeEntry); 627 log.debug("Processing route delete: {}", routeEntry);
636 IpPrefix prefix = routeEntry.prefix(); 628 IpPrefix prefix = routeEntry.prefix();
637 629
638 - // TODO check the change of logic here - remove doesn't check that
639 - // the route entry was what we expected (and we can't do this
640 - // concurrently)
641 -
642 if (bgpRoutes.remove(RouteEntry.createBinaryString(prefix))) { 630 if (bgpRoutes.remove(RouteEntry.createBinaryString(prefix))) {
643 // 631 //
644 // Only delete flows if an entry was actually removed from the 632 // Only delete flows if an entry was actually removed from the
...@@ -680,17 +668,19 @@ public class Router implements RouteListener { ...@@ -680,17 +668,19 @@ public class Router implements RouteListener {
680 } 668 }
681 669
682 /** 670 /**
683 - * This method handles the prefixes which are waiting for ARP replies for 671 + * Signals the Router that the MAC to IP mapping has potentially been
684 - * MAC addresses of next hops. 672 + * updated. This has the effect of updating the MAC address for any
673 + * installed prefixes if it has changed, as well as installing any pending
674 + * prefixes that were waiting for MAC resolution.
685 * 675 *
686 - * @param ipAddress next hop router IP address, for which we sent ARP 676 + * @param ipAddress the IP address that an event was received for
687 - * request out 677 + * @param macAddress the most recently known MAC address for the IP address
688 - * @param macAddress MAC address which is relative to the ipAddress
689 */ 678 */
690 - //@Override 679 + private void updateMac(IpAddress ipAddress, MacAddress macAddress) {
691 - // TODO change name 680 + log.debug("Received updated MAC info: {} => {}", ipAddress, macAddress);
692 - public void arpResponse(IpAddress ipAddress, MacAddress macAddress) { 681 +
693 - log.debug("Received ARP response: {} => {}", ipAddress, macAddress); 682 + // TODO here we should check whether the next hop for any of our
683 + // installed prefixes has changed, not just prefixes pending installation.
694 684
695 // We synchronize on this to prevent changes to the radix tree 685 // We synchronize on this to prevent changes to the radix tree
696 // while we're pushing intents. If the tree changes, the 686 // while we're pushing intents. If the tree changes, the
...@@ -708,8 +698,6 @@ public class Router implements RouteListener { ...@@ -708,8 +698,6 @@ public class Router implements RouteListener {
708 bgpRoutes.getValueForExactKey(binaryString); 698 bgpRoutes.getValueForExactKey(binaryString);
709 if (foundRouteEntry != null && 699 if (foundRouteEntry != null &&
710 foundRouteEntry.nextHop().equals(routeEntry.nextHop())) { 700 foundRouteEntry.nextHop().equals(routeEntry.nextHop())) {
711 - log.debug("Pushing prefix {} next hop {}",
712 - routeEntry.prefix(), routeEntry.nextHop());
713 // We only push prefix flows if the prefix is still in the 701 // We only push prefix flows if the prefix is still in the
714 // radix tree and the next hop is the same as our 702 // radix tree and the next hop is the same as our
715 // update. 703 // update.
...@@ -717,9 +705,8 @@ public class Router implements RouteListener { ...@@ -717,9 +705,8 @@ public class Router implements RouteListener {
717 // for the ARP, or the next hop could have changed. 705 // for the ARP, or the next hop could have changed.
718 addRouteIntentToNextHop(prefix, ipAddress, macAddress); 706 addRouteIntentToNextHop(prefix, ipAddress, macAddress);
719 } else { 707 } else {
720 - log.debug("Received ARP response, but {}/{} is no longer in" 708 + log.debug("{} has been revoked before the MAC was resolved",
721 - + " the radix tree", routeEntry.prefix(), 709 + routeEntry);
722 - routeEntry.nextHop());
723 } 710 }
724 } 711 }
725 } 712 }
...@@ -769,7 +756,7 @@ public class Router implements RouteListener { ...@@ -769,7 +756,7 @@ public class Router implements RouteListener {
769 event.type() == HostEvent.Type.HOST_UPDATED) { 756 event.type() == HostEvent.Type.HOST_UPDATED) {
770 Host host = event.subject(); 757 Host host = event.subject();
771 for (IpPrefix ip : host.ipAddresses()) { 758 for (IpPrefix ip : host.ipAddresses()) {
772 - arpResponse(ip.toIpAddress(), host.mac()); 759 + updateMac(ip.toIpAddress(), host.mac());
773 } 760 }
774 } 761 }
775 } 762 }
......
...@@ -26,7 +26,7 @@ import org.slf4j.Logger; ...@@ -26,7 +26,7 @@ import org.slf4j.Logger;
26 @Service 26 @Service
27 public class SdnIp implements SdnIpService { 27 public class SdnIp implements SdnIpService {
28 28
29 - private static final String SDN_ID_APP = "org.onlab.onos.sdnip"; 29 + private static final String SDN_IP_APP = "org.onlab.onos.sdnip";
30 30
31 private final Logger log = getLogger(getClass()); 31 private final Logger log = getLogger(getClass());
32 32
...@@ -53,8 +53,10 @@ public class SdnIp implements SdnIpService { ...@@ -53,8 +53,10 @@ public class SdnIp implements SdnIpService {
53 53
54 InterfaceService interfaceService = new HostToInterfaceAdaptor(hostService); 54 InterfaceService interfaceService = new HostToInterfaceAdaptor(hostService);
55 55
56 - ApplicationId appId = coreService.registerApplication(SDN_ID_APP); 56 + ApplicationId appId = coreService.registerApplication(SDN_IP_APP);
57 - peerConnectivity = new PeerConnectivityManager(appId, config, interfaceService, intentService); 57 +
58 + peerConnectivity = new PeerConnectivityManager(appId, config,
59 + interfaceService, intentService);
58 peerConnectivity.start(); 60 peerConnectivity.start();
59 61
60 router = new Router(appId, intentService, hostService, config, interfaceService); 62 router = new Router(appId, intentService, hostService, config, interfaceService);
......
...@@ -26,12 +26,12 @@ import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; ...@@ -26,12 +26,12 @@ import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
26 import org.junit.After; 26 import org.junit.After;
27 import org.junit.Before; 27 import org.junit.Before;
28 import org.junit.Test; 28 import org.junit.Test;
29 +import org.onlab.junit.TestUtils;
30 +import org.onlab.junit.TestUtils.TestUtilsException;
29 import org.onlab.onos.sdnip.RouteListener; 31 import org.onlab.onos.sdnip.RouteListener;
30 import org.onlab.onos.sdnip.RouteUpdate; 32 import org.onlab.onos.sdnip.RouteUpdate;
31 import org.onlab.packet.IpAddress; 33 import org.onlab.packet.IpAddress;
32 import org.onlab.packet.IpPrefix; 34 import org.onlab.packet.IpPrefix;
33 -import org.onlab.util.TestUtils;
34 -import org.onlab.util.TestUtils.TestUtilsException;
35 35
36 import com.google.common.net.InetAddresses; 36 import com.google.common.net.InetAddresses;
37 37
......
...@@ -6,6 +6,7 @@ import static org.hamcrest.Matchers.is; ...@@ -6,6 +6,7 @@ import static org.hamcrest.Matchers.is;
6 import static org.hamcrest.Matchers.not; 6 import static org.hamcrest.Matchers.not;
7 import static org.junit.Assert.assertEquals; 7 import static org.junit.Assert.assertEquals;
8 import static org.junit.Assert.assertThat; 8 import static org.junit.Assert.assertThat;
9 +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
9 10
10 /** 11 /**
11 * This class tests the immutability, equality, and non-equality of 12 * This class tests the immutability, equality, and non-equality of
...@@ -17,7 +18,7 @@ public class IntentIdTest { ...@@ -17,7 +18,7 @@ public class IntentIdTest {
17 */ 18 */
18 @Test 19 @Test
19 public void intentIdFollowsGuidelineForImmutableObject() { 20 public void intentIdFollowsGuidelineForImmutableObject() {
20 - ImmutableClassChecker.assertThatClassIsImmutable(IntentId.class); 21 + assertThatClassIsImmutable(IntentId.class);
21 } 22 }
22 23
23 /** 24 /**
......
...@@ -11,6 +11,7 @@ import static org.hamcrest.MatcherAssert.assertThat; ...@@ -11,6 +11,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
11 import static org.hamcrest.Matchers.equalTo; 11 import static org.hamcrest.Matchers.equalTo;
12 import static org.hamcrest.Matchers.is; 12 import static org.hamcrest.Matchers.is;
13 import static org.hamcrest.Matchers.not; 13 import static org.hamcrest.Matchers.not;
14 +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
14 import static org.onlab.onos.net.NetTestTools.hid; 15 import static org.onlab.onos.net.NetTestTools.hid;
15 16
16 /** 17 /**
...@@ -104,6 +105,6 @@ public class TestHostToHostIntent { ...@@ -104,6 +105,6 @@ public class TestHostToHostIntent {
104 */ 105 */
105 @Test 106 @Test
106 public void checkImmutability() { 107 public void checkImmutability() {
107 - ImmutableClassChecker.assertThatClassIsImmutable(HostToHostIntent.class); 108 + assertThatClassIsImmutable(HostToHostIntent.class);
108 } 109 }
109 } 110 }
......
...@@ -4,6 +4,7 @@ import static org.hamcrest.CoreMatchers.not; ...@@ -4,6 +4,7 @@ import static org.hamcrest.CoreMatchers.not;
4 import static org.hamcrest.MatcherAssert.assertThat; 4 import static org.hamcrest.MatcherAssert.assertThat;
5 import static org.hamcrest.Matchers.equalTo; 5 import static org.hamcrest.Matchers.equalTo;
6 import static org.hamcrest.Matchers.is; 6 import static org.hamcrest.Matchers.is;
7 +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
7 import static org.onlab.onos.net.NetTestTools.link; 8 import static org.onlab.onos.net.NetTestTools.link;
8 9
9 import java.util.HashSet; 10 import java.util.HashSet;
...@@ -154,6 +155,6 @@ public class TestLinkCollectionIntent { ...@@ -154,6 +155,6 @@ public class TestLinkCollectionIntent {
154 */ 155 */
155 @Test 156 @Test
156 public void checkImmutability() { 157 public void checkImmutability() {
157 - ImmutableClassChecker.assertThatClassIsImmutable(LinkCollectionIntent.class); 158 + assertThatClassIsImmutable(LinkCollectionIntent.class);
158 } 159 }
159 } 160 }
......
...@@ -15,6 +15,7 @@ import static org.hamcrest.CoreMatchers.not; ...@@ -15,6 +15,7 @@ import static org.hamcrest.CoreMatchers.not;
15 import static org.hamcrest.MatcherAssert.assertThat; 15 import static org.hamcrest.MatcherAssert.assertThat;
16 import static org.hamcrest.Matchers.equalTo; 16 import static org.hamcrest.Matchers.equalTo;
17 import static org.hamcrest.Matchers.is; 17 import static org.hamcrest.Matchers.is;
18 +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
18 import static org.onlab.onos.net.NetTestTools.connectPoint; 19 import static org.onlab.onos.net.NetTestTools.connectPoint;
19 20
20 /** 21 /**
...@@ -135,7 +136,6 @@ public class TestMultiPointToSinglePointIntent { ...@@ -135,7 +136,6 @@ public class TestMultiPointToSinglePointIntent {
135 */ 136 */
136 @Test 137 @Test
137 public void checkImmutability() { 138 public void checkImmutability() {
138 - ImmutableClassChecker. 139 + assertThatClassIsImmutable(MultiPointToSinglePointIntent.class);
139 - assertThatClassIsImmutable(MultiPointToSinglePointIntent.class);
140 } 140 }
141 } 141 }
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
35 <dependency> 35 <dependency>
36 <groupId>org.onlab.onos</groupId> 36 <groupId>org.onlab.onos</groupId>
37 <artifactId>onlab-junit</artifactId> 37 <artifactId>onlab-junit</artifactId>
38 + <scope>test</scope>
38 </dependency> 39 </dependency>
39 </dependencies> 40 </dependencies>
40 41
......
...@@ -11,6 +11,7 @@ import java.util.Arrays; ...@@ -11,6 +11,7 @@ import java.util.Arrays;
11 import java.util.Collection; 11 import java.util.Collection;
12 import java.util.Collections; 12 import java.util.Collections;
13 import java.util.Map; 13 import java.util.Map;
14 +import java.util.Set;
14 import java.util.concurrent.ExecutorService; 15 import java.util.concurrent.ExecutorService;
15 import java.util.concurrent.Executors; 16 import java.util.concurrent.Executors;
16 import java.util.concurrent.Future; 17 import java.util.concurrent.Future;
...@@ -159,6 +160,21 @@ public class DistributedFlowRuleStore ...@@ -159,6 +160,21 @@ public class DistributedFlowRuleStore
159 } 160 }
160 }); 161 });
161 162
163 + clusterCommunicator.addSubscriber(GET_DEVICE_FLOW_ENTRIES, new ClusterMessageHandler() {
164 +
165 + @Override
166 + public void handle(ClusterMessage message) {
167 + DeviceId deviceId = SERIALIZER.decode(message.payload());
168 + log.info("Received get flow entries request for {} from {}", deviceId, message.sender());
169 + Set<FlowEntry> flowEntries = getFlowEntriesInternal(deviceId);
170 + try {
171 + message.respond(SERIALIZER.encode(flowEntries));
172 + } catch (IOException e) {
173 + log.error("Failed to respond to peer's getFlowEntries request", e);
174 + }
175 + }
176 + });
177 +
162 log.info("Started"); 178 log.info("Started");
163 } 179 }
164 180
...@@ -217,9 +233,33 @@ public class DistributedFlowRuleStore ...@@ -217,9 +233,33 @@ public class DistributedFlowRuleStore
217 233
218 @Override 234 @Override
219 public synchronized Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) { 235 public synchronized Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
236 +
237 + ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(deviceId);
238 + if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) {
239 + return getFlowEntriesInternal(deviceId);
240 + }
241 +
242 + log.info("Forwarding getFlowEntries to {}, which is the primary (master) for device {}",
243 + replicaInfo.master().orNull(), deviceId);
244 +
245 + ClusterMessage message = new ClusterMessage(
246 + clusterService.getLocalNode().id(),
247 + GET_DEVICE_FLOW_ENTRIES,
248 + SERIALIZER.encode(deviceId));
249 +
250 + try {
251 + ClusterMessageResponse response = clusterCommunicator.sendAndReceive(message, replicaInfo.master().get());
252 + return SERIALIZER.decode(response.get(FLOW_RULE_STORE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
253 + } catch (IOException | TimeoutException e) {
254 + // FIXME: throw a FlowStoreException
255 + throw new RuntimeException(e);
256 + }
257 + }
258 +
259 + private Set<FlowEntry> getFlowEntriesInternal(DeviceId deviceId) {
220 Collection<? extends FlowEntry> rules = flowEntries.get(deviceId); 260 Collection<? extends FlowEntry> rules = flowEntries.get(deviceId);
221 if (rules == null) { 261 if (rules == null) {
222 - return Collections.emptyList(); 262 + return Collections.emptySet();
223 } 263 }
224 return ImmutableSet.copyOf(rules); 264 return ImmutableSet.copyOf(rules);
225 } 265 }
......
...@@ -13,4 +13,7 @@ public final class FlowStoreMessageSubjects { ...@@ -13,4 +13,7 @@ public final class FlowStoreMessageSubjects {
13 13
14 public static final MessageSubject GET_FLOW_ENTRY 14 public static final MessageSubject GET_FLOW_ENTRY
15 = new MessageSubject("peer-forward-get-flow-entry"); 15 = new MessageSubject("peer-forward-get-flow-entry");
16 +
17 + public static final MessageSubject GET_DEVICE_FLOW_ENTRIES
18 + = new MessageSubject("peer-forward-get-device-flow-entries");
16 } 19 }
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
34 <version>2.10.1</version> 34 <version>2.10.1</version>
35 <configuration> 35 <configuration>
36 <show>package</show> 36 <show>package</show>
37 - <excludePackageNames>org.onlab.thirdparty:*.impl:*.impl.*:org.onlab.onos.provider.*:org.onlab.onos.gui:org.onlab.onos.rest:org.onlab.onos.cli*:org.onlab.onos.tvue:org.onlab.onos.foo:org.onlab.onos.mobility:org.onlab.onos.proxyarp:org.onlab.onos.fwd:org.onlab.onos.ifwd:org.onlab.onos.optical:org.onlab.onos.config:org.onlab.onos.calendar:org.onlab.onos.sdnip*:org.onlab.onos.metrics</excludePackageNames> 37 + <excludePackageNames>org.onlab.thirdparty:*.impl:*.impl.*:org.onlab.onos.provider.*:org.onlab.onos.gui:org.onlab.onos.rest:org.onlab.onos.cli*:org.onlab.onos.tvue:org.onlab.onos.foo:org.onlab.onos.mobility:org.onlab.onos.proxyarp:org.onlab.onos.fwd:org.onlab.onos.ifwd:org.onlab.onos.optical:org.onlab.onos.config:org.onlab.onos.calendar:org.onlab.onos.sdnip*:org.onlab.onos.metrics:org.onlab.onos.store.*:org.onlab.onos.openflow.*</excludePackageNames>
38 <docfilessubdirs>true</docfilessubdirs> 38 <docfilessubdirs>true</docfilessubdirs>
39 <doctitle>ONOS Java API</doctitle> 39 <doctitle>ONOS Java API</doctitle>
40 <groups> 40 <groups>
......
...@@ -248,7 +248,7 @@ ...@@ -248,7 +248,7 @@
248 <dependency> 248 <dependency>
249 <groupId>org.onlab.onos</groupId> 249 <groupId>org.onlab.onos</groupId>
250 <artifactId>onlab-junit</artifactId> 250 <artifactId>onlab-junit</artifactId>
251 - <version>1.0.0-SNAPSHOT</version> 251 + <version>${project.version}</version>
252 <scope>test</scope> 252 <scope>test</scope>
253 </dependency> 253 </dependency>
254 254
......
...@@ -27,6 +27,16 @@ ...@@ -27,6 +27,16 @@
27 <artifactId>guava-testlib</artifactId> 27 <artifactId>guava-testlib</artifactId>
28 <scope>compile</scope> 28 <scope>compile</scope>
29 </dependency> 29 </dependency>
30 + <dependency>
31 + <groupId>org.hamcrest</groupId>
32 + <artifactId>hamcrest-core</artifactId>
33 + <scope>compile</scope>
34 + </dependency>
35 + <dependency>
36 + <groupId>org.hamcrest</groupId>
37 + <artifactId>hamcrest-library</artifactId>
38 + <scope>compile</scope>
39 + </dependency>
30 </dependencies> 40 </dependencies>
31 41
32 </project> 42 </project>
......
1 -package org.onlab.onos.net.intent; 1 +package org.onlab.junit;
2 -//TODO is this the right package?
3 2
4 import org.hamcrest.Description; 3 import org.hamcrest.Description;
5 import org.hamcrest.StringDescription; 4 import org.hamcrest.StringDescription;
......
1 -package org.onlab.util; 1 +package org.onlab.junit;
2 2
3 import java.lang.reflect.Constructor; 3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.Field; 4 import java.lang.reflect.Field;
......
1 +package org.onlab.junit;
2 +
3 +import org.hamcrest.Description;
4 +import org.hamcrest.StringDescription;
5 +import org.onlab.junit.TestUtils.TestUtilsException;
6 +
7 +import java.lang.reflect.Constructor;
8 +import java.lang.reflect.Method;
9 +import java.lang.reflect.Modifier;
10 +
11 +
12 +/**
13 + * Hamcrest style class for verifying that a class follows the
14 + * accepted rules for utility classes.
15 + *
16 + * The rules that are enforced for utility classes:
17 + * - the class must be declared final
18 + * - the class must have only one constructor
19 + * - the constructor must be private and inaccessible to callers
20 + * - the class must have only static methods
21 + */
22 +
23 +public class UtilityClassChecker {
24 +
25 + private String failureReason = "";
26 +
27 + /**
28 + * Method to determine if a given class is a properly specified
29 + * utility class. In addition to checking that the class meets the criteria
30 + * for utility classes, an object of the class type is allocated to force
31 + * test code coverage onto the class constructor.
32 + *
33 + * @param clazz the class to check
34 + * @return true if the given class is a properly specified utility class.
35 + */
36 + private boolean isProperlyDefinedUtilityClass(Class<?> clazz) {
37 + // class must be declared final
38 + if (!Modifier.isFinal(clazz.getModifiers())) {
39 + failureReason = "a class that is not final";
40 + return false;
41 + }
42 +
43 + // class must have only one constructor
44 + final Constructor<?>[] constructors = clazz.getDeclaredConstructors();
45 + if (constructors.length != 1) {
46 + failureReason = "a class with more than one constructor";
47 + return false;
48 + }
49 +
50 + // constructor must not be accessible outside of the class
51 + final Constructor<?> constructor = constructors[0];
52 + if (constructor.isAccessible()) {
53 + failureReason = "a class with an accessible default constructor";
54 + return false;
55 + }
56 +
57 + // constructor must be private
58 + if (!Modifier.isPrivate(constructor.getModifiers())) {
59 + failureReason = "a class with a default constructor that is not private";
60 + return false;
61 + }
62 +
63 + // class must have only static methods
64 + for (final Method method : clazz.getMethods()) {
65 + if (method.getDeclaringClass().equals(clazz)) {
66 + if (!Modifier.isStatic(method.getModifiers())) {
67 + failureReason = "a class with one or more non-static methods";
68 + return false;
69 + }
70 + }
71 +
72 + }
73 +
74 + try {
75 + final Object newObject = TestUtils.callConstructor(constructor);
76 + if (newObject == null) {
77 + failureReason = "could not instantiate a new object";
78 + return false;
79 + }
80 + } catch (TestUtilsException e) {
81 + failureReason = "could not instantiate a new object";
82 + return false;
83 + }
84 + return true;
85 + }
86 +
87 + /**
88 + * Describe why an error was reported. Uses Hamcrest style Description
89 + * interfaces.
90 + *
91 + * @param description the Description object to use for reporting the
92 + * mismatch
93 + */
94 + public void describeMismatch(Description description) {
95 + description.appendText(failureReason);
96 + }
97 +
98 + /**
99 + * Describe the source object that caused an error, using a Hamcrest
100 + * Matcher style interface. In this case, it always returns
101 + * that we are looking for a properly defined utility class.
102 + *
103 + * @param description the Description object to use to report the "to"
104 + * object
105 + */
106 + public void describeTo(Description description) {
107 + description.appendText("a properly defined utility class");
108 + }
109 +
110 + /**
111 + * Assert that the given class adheres to the utility class rules.
112 + *
113 + * @param clazz the class to check
114 + *
115 + * @throws java.lang.AssertionError if the class is not a valid
116 + * utility class
117 + */
118 + public static void assertThatClassIsUtility(Class<?> clazz) {
119 + final UtilityClassChecker checker = new UtilityClassChecker();
120 + if (!checker.isProperlyDefinedUtilityClass(clazz)) {
121 + final Description toDescription = new StringDescription();
122 + final Description mismatchDescription = new StringDescription();
123 +
124 + checker.describeTo(toDescription);
125 + checker.describeMismatch(mismatchDescription);
126 + final String reason =
127 + "\n" +
128 + "Expected: is \"" + toDescription.toString() + "\"\n" +
129 + " but : was \"" + mismatchDescription.toString() + "\"";
130 +
131 + throw new AssertionError(reason);
132 + }
133 + }
134 +}
1 +package org.onlab.junit;
2 +
3 +import org.junit.Test;
4 +
5 +import static org.hamcrest.MatcherAssert.assertThat;
6 +import static org.hamcrest.Matchers.containsString;
7 +import static org.hamcrest.Matchers.is;
8 +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
9 +
10 +/**
11 + * Set of unit tests to check the implementation of the immutable class
12 + * checker.
13 + */
14 +public class ImmutableClassCheckerTest {
15 + /**
16 + * Test class for non final class check.
17 + */
18 + // CHECKSTYLE IGNORE FinalClass FOR NEXT 1 LINES
19 + static class NonFinal {
20 + private NonFinal() { }
21 + }
22 +
23 + /**
24 + * Check that a non final class correctly produces an error.
25 + * @throws Exception if any of the reflection lookups fail.
26 + */
27 + @Test
28 + public void testNonFinalClass() throws Exception {
29 + boolean gotException = false;
30 + try {
31 + assertThatClassIsImmutable(NonFinal.class);
32 + } catch (AssertionError assertion) {
33 + assertThat(assertion.getMessage(),
34 + containsString("is not final"));
35 + gotException = true;
36 + }
37 + assertThat(gotException, is(true));
38 + }
39 +
40 + /**
41 + * Test class for non private member class check.
42 + */
43 + static final class FinalProtectedMember {
44 + protected final int x = 0;
45 + }
46 +
47 + /**
48 + * Check that a final class with a non-private member is properly detected.
49 + *
50 + * @throws Exception if any of the reflection lookups fail.
51 + */
52 + @Test
53 + public void testFinalProtectedMember() throws Exception {
54 + boolean gotException = false;
55 + try {
56 + assertThatClassIsImmutable(FinalProtectedMember.class);
57 + } catch (AssertionError assertion) {
58 + assertThat(assertion.getMessage(),
59 + containsString("a field named 'x' that is not private"));
60 + gotException = true;
61 + }
62 + assertThat(gotException, is(true));
63 + }
64 +
65 + /**
66 + * Test class for non private member class check.
67 + */
68 + static final class NotFinalPrivateMember {
69 + private int x = 0;
70 + }
71 +
72 + /**
73 + * Check that a final class with a non-final private
74 + * member is properly detected.
75 + *
76 + * @throws Exception if any of the reflection lookups fail.
77 + */
78 + @Test
79 + public void testNotFinalPrivateMember() throws Exception {
80 + boolean gotException = false;
81 + try {
82 + assertThatClassIsImmutable(NotFinalPrivateMember.class);
83 + } catch (AssertionError assertion) {
84 + assertThat(assertion.getMessage(),
85 + containsString("a field named 'x' that is not final"));
86 + gotException = true;
87 + }
88 + assertThat(gotException, is(true));
89 + }
90 +
91 + /**
92 + * Test class for non private member class check.
93 + */
94 + static final class ClassWithSetter {
95 + private final int x = 0;
96 + public void setX(int newX) {
97 + }
98 + }
99 +
100 + /**
101 + * Check that a final class with a final private
102 + * member that is modifyable by a setter is properly detected.
103 + *
104 + * @throws Exception if any of the reflection lookups fail.
105 + */
106 + @Test
107 + public void testClassWithSetter() throws Exception {
108 + boolean gotException = false;
109 + try {
110 + assertThatClassIsImmutable(ClassWithSetter.class);
111 + } catch (AssertionError assertion) {
112 + assertThat(assertion.getMessage(),
113 + containsString("a class with a setter named 'setX'"));
114 + gotException = true;
115 + }
116 + assertThat(gotException, is(true));
117 + }
118 +
119 +}
120 +
1 -package org.onlab.util; 1 +package org.onlab.junit;
2 2
3 import static org.junit.Assert.assertArrayEquals; 3 import static org.junit.Assert.assertArrayEquals;
4 import static org.junit.Assert.assertEquals; 4 import static org.junit.Assert.assertEquals;
...@@ -6,7 +6,7 @@ import static org.junit.Assert.assertNull; ...@@ -6,7 +6,7 @@ import static org.junit.Assert.assertNull;
6 6
7 import org.junit.Before; 7 import org.junit.Before;
8 import org.junit.Test; 8 import org.junit.Test;
9 -import org.onlab.util.TestUtils.TestUtilsException; 9 +import org.onlab.junit.TestUtils.TestUtilsException;
10 10
11 /** 11 /**
12 * Test and usage examples for TestUtils. 12 * Test and usage examples for TestUtils.
......
1 +package org.onlab.junit;
2 +
3 +import org.junit.Test;
4 +
5 +import static org.hamcrest.MatcherAssert.assertThat;
6 +import static org.hamcrest.Matchers.containsString;
7 +import static org.hamcrest.Matchers.is;
8 +import static org.onlab.junit.UtilityClassChecker.assertThatClassIsUtility;
9 +
10 +/**
11 + * Set of unit tests to check the implementation of the utility class
12 + * checker.
13 + */
14 +public class UtilityClassCheckerTest {
15 +
16 + // CHECKSTYLE:OFF test data intentionally not final
17 + /**
18 + * Test class for non final class check.
19 + */
20 + static class NonFinal {
21 + private NonFinal() { }
22 + }
23 + // CHECKSTYLE:ON
24 +
25 + /**
26 + * Check that a non final class correctly produces an error.
27 + * @throws Exception if any of the reflection lookups fail.
28 + */
29 + @Test
30 + public void testNonFinalClass() throws Exception {
31 + boolean gotException = false;
32 + try {
33 + assertThatClassIsUtility(NonFinal.class);
34 + } catch (AssertionError assertion) {
35 + assertThat(assertion.getMessage(),
36 + containsString("is not final"));
37 + gotException = true;
38 + }
39 + assertThat(gotException, is(true));
40 + }
41 +
42 + /**
43 + * Test class for final no constructor class check.
44 + */
45 + static final class FinalNoConstructor {
46 + }
47 +
48 + /**
49 + * Check that a final class with no declared constructor correctly produces
50 + * an error. In this case, the compiler generates a default constructor
51 + * for you, but the constructor is 'protected' and will fail the check.
52 + *
53 + * @throws Exception if any of the reflection lookups fail.
54 + */
55 + @Test
56 + public void testFinalNoConstructorClass() throws Exception {
57 + boolean gotException = false;
58 + try {
59 + assertThatClassIsUtility(FinalNoConstructor.class);
60 + } catch (AssertionError assertion) {
61 + assertThat(assertion.getMessage(),
62 + containsString("class with a default constructor that " +
63 + "is not private"));
64 + gotException = true;
65 + }
66 + assertThat(gotException, is(true));
67 + }
68 +
69 + /**
70 + * Test class for class with more than one constructor check.
71 + */
72 + static final class TwoConstructors {
73 + private TwoConstructors() { }
74 + private TwoConstructors(int x) { }
75 + }
76 +
77 + /**
78 + * Check that a non static class correctly produces an error.
79 + * @throws Exception if any of the reflection lookups fail.
80 + */
81 + @Test
82 + public void testOnlyOneConstructor() throws Exception {
83 + boolean gotException = false;
84 + try {
85 + assertThatClassIsUtility(TwoConstructors.class);
86 + } catch (AssertionError assertion) {
87 + assertThat(assertion.getMessage(),
88 + containsString("more than one constructor"));
89 + gotException = true;
90 + }
91 + assertThat(gotException, is(true));
92 + }
93 +
94 + /**
95 + * Test class with a non private constructor.
96 + */
97 + static final class NonPrivateConstructor {
98 + protected NonPrivateConstructor() { }
99 + }
100 +
101 + /**
102 + * Check that a class with a non private constructor correctly
103 + * produces an error.
104 + * @throws Exception if any of the reflection lookups fail.
105 + */
106 + @Test
107 + public void testNonPrivateConstructor() throws Exception {
108 +
109 + boolean gotException = false;
110 + try {
111 + assertThatClassIsUtility(NonPrivateConstructor.class);
112 + } catch (AssertionError assertion) {
113 + assertThat(assertion.getMessage(),
114 + containsString("constructor that is not private"));
115 + gotException = true;
116 + }
117 + assertThat(gotException, is(true));
118 + }
119 +
120 + /**
121 + * Test class with a non static method.
122 + */
123 + static final class NonStaticMethod {
124 + private NonStaticMethod() { }
125 + public void aPublicMethod() { }
126 + }
127 +
128 + /**
129 + * Check that a class with a non static method correctly produces an error.
130 + * @throws Exception if any of the reflection lookups fail.
131 + */
132 + @Test
133 + public void testNonStaticMethod() throws Exception {
134 +
135 + boolean gotException = false;
136 + try {
137 + assertThatClassIsUtility(NonStaticMethod.class);
138 + } catch (AssertionError assertion) {
139 + assertThat(assertion.getMessage(),
140 + containsString("one or more non-static methods"));
141 + gotException = true;
142 + }
143 + assertThat(gotException, is(true));
144 + }
145 +}
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
24 <dependency> 24 <dependency>
25 <groupId>org.onlab.onos</groupId> 25 <groupId>org.onlab.onos</groupId>
26 <artifactId>onlab-junit</artifactId> 26 <artifactId>onlab-junit</artifactId>
27 + <scope>test</scope>
27 </dependency> 28 </dependency>
28 <dependency> 29 <dependency>
29 <groupId>io.netty</groupId> 30 <groupId>io.netty</groupId>
......
1 +package org.onlab.packet;
2 +
3 +import java.nio.ByteBuffer;
4 +import static com.google.common.base.Preconditions.checkNotNull;
5 +
6 +/**
7 + * The class representing an IPv4 address.
8 + * This class is immutable.
9 + */
10 +public final class Ip4Address implements Comparable<Ip4Address> {
11 + private final int value;
12 +
13 + /** The length of the address in bytes (octets). */
14 + public static final int BYTE_LENGTH = 4;
15 +
16 + /** The length of the address in bits. */
17 + public static final int BIT_LENGTH = BYTE_LENGTH * Byte.SIZE;
18 +
19 + /**
20 + * Default constructor.
21 + */
22 + public Ip4Address() {
23 + this.value = 0;
24 + }
25 +
26 + /**
27 + * Copy constructor.
28 + *
29 + * @param other the object to copy from
30 + */
31 + public Ip4Address(Ip4Address other) {
32 + this.value = other.value;
33 + }
34 +
35 + /**
36 + * Constructor from an integer value.
37 + *
38 + * @param value the value to use
39 + */
40 + public Ip4Address(int value) {
41 + this.value = value;
42 + }
43 +
44 + /**
45 + * Constructor from a byte array with the IPv4 address stored in network
46 + * byte order (i.e., the most significant byte first).
47 + *
48 + * @param value the value to use
49 + */
50 + public Ip4Address(byte[] value) {
51 + this(value, 0);
52 + }
53 +
54 + /**
55 + * Constructor from a byte array with the IPv4 address stored in network
56 + * byte order (i.e., the most significant byte first), and a given offset
57 + * from the beginning of the byte array.
58 + *
59 + * @param value the value to use
60 + * @param offset the offset in bytes from the beginning of the byte array
61 + */
62 + public Ip4Address(byte[] value, int offset) {
63 + checkNotNull(value);
64 +
65 + // Verify the arguments
66 + if ((offset < 0) || (offset + BYTE_LENGTH > value.length)) {
67 + String msg;
68 + if (value.length < BYTE_LENGTH) {
69 + msg = "Invalid IPv4 address array: array length: " +
70 + value.length + ". Must be at least " + BYTE_LENGTH;
71 + } else {
72 + msg = "Invalid IPv4 address array: array offset: " +
73 + offset + ". Must be in the interval [0, " +
74 + (value.length - BYTE_LENGTH) + "]";
75 + }
76 + throw new IllegalArgumentException(msg);
77 + }
78 +
79 + // Read the address
80 + ByteBuffer bb = ByteBuffer.wrap(value);
81 + this.value = bb.getInt(offset);
82 + }
83 +
84 + /**
85 + * Constructs an IPv4 address from a string representation of the address.
86 + *<p>
87 + * Example: "1.2.3.4"
88 + *
89 + * @param value the value to use
90 + */
91 + public Ip4Address(String value) {
92 + checkNotNull(value);
93 +
94 + String[] splits = value.split("\\.");
95 + if (splits.length != 4) {
96 + final String msg = "Invalid IPv4 address string: " + value;
97 + throw new IllegalArgumentException(msg);
98 + }
99 +
100 + int result = 0;
101 + for (int i = 0; i < BYTE_LENGTH; i++) {
102 + result |= Integer.parseInt(splits[i]) <<
103 + ((BYTE_LENGTH - (i + 1)) * Byte.SIZE);
104 + }
105 + this.value = result;
106 + }
107 +
108 + /**
109 + * Gets the IPv4 address as a byte array.
110 + *
111 + * @return a byte array with the IPv4 address stored in network byte order
112 + * (i.e., the most significant byte first).
113 + */
114 + public byte[] toOctets() {
115 + return ByteBuffer.allocate(BYTE_LENGTH).putInt(value).array();
116 + }
117 +
118 + /**
119 + * Creates an IPv4 network mask prefix.
120 + *
121 + * @param prefixLen the length of the mask prefix. Must be in the interval
122 + * [0, 32].
123 + * @return a new IPv4 address that contains a mask prefix of the
124 + * specified length
125 + */
126 + public static Ip4Address makeMaskPrefix(int prefixLen) {
127 + // Verify the prefix length
128 + if ((prefixLen < 0) || (prefixLen > Ip4Address.BIT_LENGTH)) {
129 + final String msg = "Invalid IPv4 prefix length: " + prefixLen +
130 + ". Must be in the interval [0, 32].";
131 + throw new IllegalArgumentException(msg);
132 + }
133 +
134 + long v =
135 + (0xffffffffL << (Ip4Address.BIT_LENGTH - prefixLen)) & 0xffffffffL;
136 + return new Ip4Address((int) v);
137 + }
138 +
139 + /**
140 + * Creates an IPv4 address by masking it with a network mask of given
141 + * mask length.
142 + *
143 + * @param addr the address to mask
144 + * @param prefixLen the length of the mask prefix. Must be in the interval
145 + * [0, 32].
146 + * @return a new IPv4 address that is masked with a mask prefix of the
147 + * specified length
148 + */
149 + public static Ip4Address makeMaskedAddress(final Ip4Address addr,
150 + int prefixLen) {
151 + Ip4Address mask = Ip4Address.makeMaskPrefix(prefixLen);
152 + long v = addr.value & mask.value;
153 +
154 + return new Ip4Address((int) v);
155 + }
156 +
157 + /**
158 + * Gets the value of the IPv4 address.
159 + *
160 + * @return the value of the IPv4 address
161 + */
162 + public int getValue() {
163 + return value;
164 + }
165 +
166 + /**
167 + * Converts the IPv4 value to a '.' separated string.
168 + *
169 + * @return the IPv4 value as a '.' separated string
170 + */
171 + @Override
172 + public String toString() {
173 + return ((this.value >> 24) & 0xff) + "." +
174 + ((this.value >> 16) & 0xff) + "." +
175 + ((this.value >> 8) & 0xff) + "." +
176 + (this.value & 0xff);
177 + }
178 +
179 + @Override
180 + public boolean equals(Object o) {
181 + if (!(o instanceof Ip4Address)) {
182 + return false;
183 + }
184 + Ip4Address other = (Ip4Address) o;
185 + if (this.value != other.value) {
186 + return false;
187 + }
188 + return true;
189 + }
190 +
191 + @Override
192 + public int hashCode() {
193 + return this.value;
194 + }
195 +
196 + @Override
197 + public int compareTo(Ip4Address o) {
198 + Long lv = ((long) this.value) & 0xffffffffL;
199 + Long rv = ((long) o.value) & 0xffffffffL;
200 + return lv.compareTo(rv);
201 + }
202 +}
1 +package org.onlab.packet;
2 +
3 +import java.util.Objects;
4 +
5 +/**
6 + * The class representing an IPv4 network address.
7 + * This class is immutable.
8 + */
9 +public final class Ip4Prefix {
10 + private final Ip4Address address; // The IPv4 address
11 + private final short prefixLen; // The prefix length
12 +
13 + /**
14 + * Default constructor.
15 + */
16 + public Ip4Prefix() {
17 + this.address = new Ip4Address();
18 + this.prefixLen = 0;
19 + }
20 +
21 + /**
22 + * Copy constructor.
23 + *
24 + * @param other the object to copy from
25 + */
26 + public Ip4Prefix(Ip4Prefix other) {
27 + this.address = new Ip4Address(other.address);
28 + this.prefixLen = other.prefixLen;
29 + }
30 +
31 + /**
32 + * Constructor for a given address and prefix length.
33 + *
34 + * @param address the address to use
35 + * @param prefixLen the prefix length to use
36 + */
37 + public Ip4Prefix(Ip4Address address, short prefixLen) {
38 + this.address = Ip4Address.makeMaskedAddress(address, prefixLen);
39 + this.prefixLen = prefixLen;
40 + }
41 +
42 + /**
43 + * Constructs an IPv4 prefix from a string representation of the
44 + * prefix.
45 + *<p>
46 + * Example: "1.2.0.0/16"
47 + *
48 + * @param value the value to use
49 + */
50 + public Ip4Prefix(String value) {
51 + String[] splits = value.split("/");
52 + if (splits.length != 2) {
53 + throw new IllegalArgumentException("Specified IPv4 prefix must contain an IPv4 " +
54 + "address and a prefix length separated by '/'");
55 + }
56 + this.prefixLen = Short.decode(splits[1]);
57 + this.address = Ip4Address.makeMaskedAddress(new Ip4Address(splits[0]),
58 + this.prefixLen);
59 + }
60 +
61 + /**
62 + * Gets the address value of the IPv4 prefix.
63 + *
64 + * @return the address value of the IPv4 prefix
65 + */
66 + public Ip4Address getAddress() {
67 + return address;
68 + }
69 +
70 + /**
71 + * Gets the prefix length value of the IPv4 prefix.
72 + *
73 + * @return the prefix length value of the IPv4 prefix
74 + */
75 + public short getPrefixLen() {
76 + return prefixLen;
77 + }
78 +
79 + /**
80 + * Converts the IPv4 prefix value to an "address/prefixLen" string.
81 + *
82 + * @return the IPv4 prefix value as an "address/prefixLen" string
83 + */
84 + @Override
85 + public String toString() {
86 + return this.address.toString() + "/" + this.prefixLen;
87 + }
88 +
89 + /**
90 + * Compares the value of two Ip4Prefix objects.
91 + * <p/>
92 + * Note the value of the IPv4 address is compared directly between the
93 + * objects, and must match exactly for the objects to be considered equal.
94 + * This may result in objects which represent the same IP prefix being
95 + * classified as unequal, because the unsignificant bits of the address
96 + * field don't match (the bits to the right of the prefix length).
97 + * <p/>
98 + * TODO Change this behavior so that objects that represent the same prefix
99 + * are classified as equal according to this equals method.
100 + *
101 + * @see Object#equals(Object)
102 + */
103 + @Override
104 + public boolean equals(Object other) {
105 + if (other == this) {
106 + return true;
107 + }
108 +
109 + if (!(other instanceof Ip4Prefix)) {
110 + return false;
111 + }
112 +
113 + Ip4Prefix otherIp4Prefix = (Ip4Prefix) other;
114 +
115 + return Objects.equals(this.address, otherIp4Prefix.address)
116 + && this.prefixLen == otherIp4Prefix.prefixLen;
117 + }
118 +
119 + @Override
120 + public int hashCode() {
121 + return Objects.hash(address, prefixLen);
122 + }
123 +}
1 +package org.onlab.packet;
2 +
3 +import java.net.InetAddress;
4 +import java.net.UnknownHostException;
5 +import java.nio.ByteBuffer;
6 +import java.util.Objects;
7 +
8 +import com.google.common.net.InetAddresses;
9 +import com.google.common.primitives.UnsignedLongs;
10 +
11 +import static com.google.common.base.Preconditions.checkNotNull;
12 +import static com.google.common.base.Preconditions.checkState;
13 +
14 +/**
15 + * The class representing an IPv6 address.
16 + * This class is immutable.
17 + */
18 +public final class Ip6Address implements Comparable<Ip6Address> {
19 + private final long valueHigh; // The higher (more significant) 64 bits
20 + private final long valueLow; // The lower (less significant) 64 bits
21 +
22 + /** The length of the address in bytes (octets). */
23 + public static final int BYTE_LENGTH = 16;
24 +
25 + /** The length of the address in bits. */
26 + public static final int BIT_LENGTH = BYTE_LENGTH * Byte.SIZE;
27 +
28 + /**
29 + * Default constructor.
30 + */
31 + public Ip6Address() {
32 + this.valueHigh = 0;
33 + this.valueLow = 0;
34 + }
35 +
36 + /**
37 + * Copy constructor.
38 + *
39 + * @param other the object to copy from
40 + */
41 + public Ip6Address(Ip6Address other) {
42 + this.valueHigh = other.valueHigh;
43 + this.valueLow = other.valueLow;
44 + }
45 +
46 + /**
47 + * Constructor from integer values.
48 + *
49 + * @param valueHigh the higher (more significant) 64 bits of the address
50 + * @param valueLow the lower (less significant) 64 bits of the address
51 + */
52 + public Ip6Address(long valueHigh, long valueLow) {
53 + this.valueHigh = valueHigh;
54 + this.valueLow = valueLow;
55 + }
56 +
57 + /**
58 + * Constructor from a byte array with the IPv6 address stored in network
59 + * byte order (i.e., the most significant byte first).
60 + *
61 + * @param value the value to use
62 + */
63 + public Ip6Address(byte[] value) {
64 + this(value, 0);
65 + }
66 +
67 + /**
68 + * Constructor from a byte array with the IPv6 address stored in network
69 + * byte order (i.e., the most significant byte first), and a given offset
70 + * from the beginning of the byte array.
71 + *
72 + * @param value the value to use
73 + * @param offset the offset in bytes from the beginning of the byte array
74 + */
75 + public Ip6Address(byte[] value, int offset) {
76 + checkNotNull(value);
77 +
78 + // Verify the arguments
79 + if ((offset < 0) || (offset + BYTE_LENGTH > value.length)) {
80 + String msg;
81 + if (value.length < BYTE_LENGTH) {
82 + msg = "Invalid IPv6 address array: array length: " +
83 + value.length + ". Must be at least " + BYTE_LENGTH;
84 + } else {
85 + msg = "Invalid IPv6 address array: array offset: " +
86 + offset + ". Must be in the interval [0, " +
87 + (value.length - BYTE_LENGTH) + "]";
88 + }
89 + throw new IllegalArgumentException(msg);
90 + }
91 +
92 + // Read the address
93 + ByteBuffer bb = ByteBuffer.wrap(value);
94 + bb.position(offset);
95 + this.valueHigh = bb.getLong();
96 + this.valueLow = bb.getLong();
97 + }
98 +
99 + /**
100 + * Constructs an IPv6 address from a string representation of the address.
101 + *<p>
102 + * Example: "1111:2222::8888"
103 + *
104 + * @param value the value to use
105 + */
106 + public Ip6Address(String value) {
107 + checkNotNull(value);
108 +
109 + if (value.isEmpty()) {
110 + final String msg = "Specified IPv6 cannot be an empty string";
111 + throw new IllegalArgumentException(msg);
112 + }
113 + InetAddress addr = null;
114 + try {
115 + addr = InetAddresses.forString(value);
116 + } catch (IllegalArgumentException e) {
117 + final String msg = "Invalid IPv6 address string: " + value;
118 + throw new IllegalArgumentException(msg);
119 + }
120 + byte[] bytes = addr.getAddress();
121 + ByteBuffer bb = ByteBuffer.wrap(bytes);
122 + this.valueHigh = bb.getLong();
123 + this.valueLow = bb.getLong();
124 + }
125 +
126 + /**
127 + * Gets the IPv6 address as a byte array.
128 + *
129 + * @return a byte array with the IPv6 address stored in network byte order
130 + * (i.e., the most significant byte first).
131 + */
132 + public byte[] toOctets() {
133 + return ByteBuffer.allocate(BYTE_LENGTH)
134 + .putLong(valueHigh).putLong(valueLow).array();
135 + }
136 +
137 + /**
138 + * Creates an IPv6 network mask prefix.
139 + *
140 + * @param prefixLen the length of the mask prefix. Must be in the interval
141 + * [0, 128].
142 + * @return a new IPv6 address that contains a mask prefix of the
143 + * specified length
144 + */
145 + public static Ip6Address makeMaskPrefix(int prefixLen) {
146 + long vh, vl;
147 +
148 + // Verify the prefix length
149 + if ((prefixLen < 0) || (prefixLen > Ip6Address.BIT_LENGTH)) {
150 + final String msg = "Invalid IPv6 prefix length: " + prefixLen +
151 + ". Must be in the interval [0, 128].";
152 + throw new IllegalArgumentException(msg);
153 + }
154 +
155 + if (prefixLen == 0) {
156 + //
157 + // NOTE: Apparently, the result of "<< 64" shifting to the left
158 + // results in all 1s instead of all 0s, hence we handle it as
159 + // a special case.
160 + //
161 + vh = 0;
162 + vl = 0;
163 + } else if (prefixLen <= 64) {
164 + vh = (0xffffffffffffffffL << (64 - prefixLen)) & 0xffffffffffffffffL;
165 + vl = 0;
166 + } else {
167 + vh = -1L; // All 1s
168 + vl = (0xffffffffffffffffL << (128 - prefixLen)) & 0xffffffffffffffffL;
169 + }
170 + return new Ip6Address(vh, vl);
171 + }
172 +
173 + /**
174 + * Creates an IPv6 address by masking it with a network mask of given
175 + * mask length.
176 + *
177 + * @param addr the address to mask
178 + * @param prefixLen the length of the mask prefix. Must be in the interval
179 + * [0, 128].
180 + * @return a new IPv6 address that is masked with a mask prefix of the
181 + * specified length
182 + */
183 + public static Ip6Address makeMaskedAddress(final Ip6Address addr,
184 + int prefixLen) {
185 + Ip6Address mask = Ip6Address.makeMaskPrefix(prefixLen);
186 + long vh = addr.valueHigh & mask.valueHigh;
187 + long vl = addr.valueLow & mask.valueLow;
188 +
189 + return new Ip6Address(vh, vl);
190 + }
191 +
192 + /**
193 + * Gets the value of the higher (more significant) 64 bits of the address.
194 + *
195 + * @return the value of the higher (more significant) 64 bits of the
196 + * address
197 + */
198 + public long getValueHigh() {
199 + return valueHigh;
200 + }
201 +
202 + /**
203 + * Gets the value of the lower (less significant) 64 bits of the address.
204 + *
205 + * @return the value of the lower (less significant) 64 bits of the
206 + * address
207 + */
208 + public long getValueLow() {
209 + return valueLow;
210 + }
211 +
212 + /**
213 + * Converts the IPv6 value to a ':' separated string.
214 + *
215 + * @return the IPv6 value as a ':' separated string
216 + */
217 + @Override
218 + public String toString() {
219 + ByteBuffer bb = ByteBuffer.allocate(Ip6Address.BYTE_LENGTH);
220 + bb.putLong(valueHigh);
221 + bb.putLong(valueLow);
222 + InetAddress inetAddr = null;
223 + try {
224 + inetAddr = InetAddress.getByAddress(bb.array());
225 + } catch (UnknownHostException e) {
226 + // Should never happen
227 + checkState(false, "Internal error: Ip6Address.toString()");
228 + return "::";
229 + }
230 + return InetAddresses.toAddrString(inetAddr);
231 + }
232 +
233 + @Override
234 + public boolean equals(Object o) {
235 + if (!(o instanceof Ip6Address)) {
236 + return false;
237 + }
238 + Ip6Address other = (Ip6Address) o;
239 + return this.valueHigh == other.valueHigh
240 + && this.valueLow == other.valueLow;
241 + }
242 +
243 + @Override
244 + public int hashCode() {
245 + return Objects.hash(valueHigh, valueLow);
246 + }
247 +
248 + @Override
249 + public int compareTo(Ip6Address o) {
250 + // Compare the high-order 64-bit value
251 + if (this.valueHigh != o.valueHigh) {
252 + return UnsignedLongs.compare(this.valueHigh, o.valueHigh);
253 + }
254 + // Compare the low-order 64-bit value
255 + if (this.valueLow != o.valueLow) {
256 + return UnsignedLongs.compare(this.valueLow, o.valueLow);
257 + }
258 + return 0;
259 + }
260 +}
1 +package org.onlab.packet;
2 +
3 +import java.util.Objects;
4 +
5 +/**
6 + * The class representing an IPv6 network address.
7 + * This class is immutable.
8 + */
9 +public final class Ip6Prefix {
10 + private final Ip6Address address; // The IPv6 address
11 + private final short prefixLen; // The prefix length
12 +
13 + /**
14 + * Default constructor.
15 + */
16 + public Ip6Prefix() {
17 + this.address = new Ip6Address();
18 + this.prefixLen = 0;
19 + }
20 +
21 + /**
22 + * Copy constructor.
23 + *
24 + * @param other the object to copy from
25 + */
26 + public Ip6Prefix(Ip6Prefix other) {
27 + this.address = new Ip6Address(other.address);
28 + this.prefixLen = other.prefixLen;
29 + }
30 +
31 + /**
32 + * Constructor for a given address and prefix length.
33 + *
34 + * @param address the address to use
35 + * @param prefixLen the prefix length to use
36 + */
37 + public Ip6Prefix(Ip6Address address, short prefixLen) {
38 + this.address = Ip6Address.makeMaskedAddress(address, prefixLen);
39 + this.prefixLen = prefixLen;
40 + }
41 +
42 + /**
43 + * Constructs an IPv6 prefix from a string representation of the
44 + * prefix.
45 + *<p>
46 + * Example: "1111:2222::/32"
47 + *
48 + * @param value the value to use
49 + */
50 + public Ip6Prefix(String value) {
51 + String[] splits = value.split("/");
52 + if (splits.length != 2) {
53 + throw new IllegalArgumentException("Specified IPv6 prefix must contain an IPv6 " +
54 + "address and a prefix length separated by '/'");
55 + }
56 + this.prefixLen = Short.decode(splits[1]);
57 + this.address = Ip6Address.makeMaskedAddress(new Ip6Address(splits[0]),
58 + this.prefixLen);
59 + }
60 +
61 + /**
62 + * Gets the address value of the IPv6 prefix.
63 + *
64 + * @return the address value of the IPv6 prefix
65 + */
66 + public Ip6Address getAddress() {
67 + return address;
68 + }
69 +
70 + /**
71 + * Gets the prefix length value of the IPv6 prefix.
72 + *
73 + * @return the prefix length value of the IPv6 prefix
74 + */
75 + public short getPrefixLen() {
76 + return prefixLen;
77 + }
78 +
79 + /**
80 + * Converts the IPv6 prefix value to an "address/prefixLen" string.
81 + *
82 + * @return the IPv6 prefix value as an "address/prefixLen" string
83 + */
84 + @Override
85 + public String toString() {
86 + return this.address.toString() + "/" + this.prefixLen;
87 + }
88 +
89 + /**
90 + * Compares the value of two Ip6Prefix objects.
91 + * <p/>
92 + * Note the value of the IPv6 address is compared directly between the
93 + * objects, and must match exactly for the objects to be considered equal.
94 + * This may result in objects which represent the same IP prefix being
95 + * classified as unequal, because the unsignificant bits of the address
96 + * field don't match (the bits to the right of the prefix length).
97 + * <p/>
98 + * TODO Change this behavior so that objects that represent the same prefix
99 + * are classified as equal according to this equals method.
100 + *
101 + * @see Object#equals(Object)
102 + */
103 + @Override
104 + public boolean equals(Object other) {
105 + if (other == this) {
106 + return true;
107 + }
108 +
109 + if (!(other instanceof Ip6Prefix)) {
110 + return false;
111 + }
112 +
113 + Ip6Prefix otherIp6Prefix = (Ip6Prefix) other;
114 +
115 + return Objects.equals(this.address, otherIp6Prefix.address)
116 + && this.prefixLen == otherIp6Prefix.prefixLen;
117 + }
118 +
119 + @Override
120 + public int hashCode() {
121 + return Objects.hash(address, prefixLen);
122 + }
123 +}
This diff is collapsed. Click to expand it.
1 +package org.onlab.packet;
2 +
3 +import org.junit.Test;
4 +
5 +import static org.hamcrest.Matchers.equalTo;
6 +import static org.hamcrest.Matchers.is;
7 +import static org.hamcrest.Matchers.not;
8 +import static org.junit.Assert.assertThat;
9 +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
10 +
11 +/**
12 + * Tests for class {@link Ip4Prefix}.
13 + */
14 +public class Ip4PrefixTest {
15 + /**
16 + * Tests the immutability of {@link Ip4Prefix}.
17 + */
18 + @Test
19 + public void testImmutable() {
20 + assertThatClassIsImmutable(Ip4Prefix.class);
21 + }
22 +
23 + /**
24 + * Tests default class constructor.
25 + */
26 + @Test
27 + public void testDefaultConstructor() {
28 + Ip4Prefix ip4prefix = new Ip4Prefix();
29 + assertThat(ip4prefix.toString(), is("0.0.0.0/0"));
30 + }
31 +
32 + /**
33 + * Tests valid class copy constructor.
34 + */
35 + @Test
36 + public void testCopyConstructor() {
37 + Ip4Prefix fromAddr = new Ip4Prefix("1.2.3.0/24");
38 + Ip4Prefix ip4prefix = new Ip4Prefix(fromAddr);
39 + assertThat(ip4prefix.toString(), is("1.2.3.0/24"));
40 +
41 + fromAddr = new Ip4Prefix("0.0.0.0/0");
42 + ip4prefix = new Ip4Prefix(fromAddr);
43 + assertThat(ip4prefix.toString(), is("0.0.0.0/0"));
44 +
45 + fromAddr = new Ip4Prefix("255.255.255.255/32");
46 + ip4prefix = new Ip4Prefix(fromAddr);
47 + assertThat(ip4prefix.toString(), is("255.255.255.255/32"));
48 + }
49 +
50 + /**
51 + * Tests invalid class copy constructor for a null object to copy from.
52 + */
53 + @Test(expected = NullPointerException.class)
54 + public void testInvalidConstructorNullObject() {
55 + Ip4Prefix fromAddr = null;
56 + Ip4Prefix ip4prefix = new Ip4Prefix(fromAddr);
57 + }
58 +
59 + /**
60 + * Tests valid class constructor for an address and prefix length.
61 + */
62 + @Test
63 + public void testConstructorForAddressAndPrefixLength() {
64 + Ip4Prefix ip4prefix =
65 + new Ip4Prefix(new Ip4Address("1.2.3.0"), (short) 24);
66 + assertThat(ip4prefix.toString(), is("1.2.3.0/24"));
67 +
68 + ip4prefix = new Ip4Prefix(new Ip4Address("1.2.3.4"), (short) 24);
69 + assertThat(ip4prefix.toString(), is("1.2.3.0/24"));
70 +
71 + ip4prefix = new Ip4Prefix(new Ip4Address("1.2.3.5"), (short) 32);
72 + assertThat(ip4prefix.toString(), is("1.2.3.5/32"));
73 +
74 + ip4prefix = new Ip4Prefix(new Ip4Address("0.0.0.0"), (short) 0);
75 + assertThat(ip4prefix.toString(), is("0.0.0.0/0"));
76 +
77 + ip4prefix =
78 + new Ip4Prefix(new Ip4Address("255.255.255.255"), (short) 32);
79 + assertThat(ip4prefix.toString(), is("255.255.255.255/32"));
80 + }
81 +
82 + /**
83 + * Tests valid class constructor for a string.
84 + */
85 + @Test
86 + public void testConstructorForString() {
87 + Ip4Prefix ip4prefix = new Ip4Prefix("1.2.3.0/24");
88 + assertThat(ip4prefix.toString(), is("1.2.3.0/24"));
89 +
90 + ip4prefix = new Ip4Prefix("1.2.3.4/24");
91 + assertThat(ip4prefix.toString(), is("1.2.3.0/24"));
92 +
93 + ip4prefix = new Ip4Prefix("1.2.3.5/32");
94 + assertThat(ip4prefix.toString(), is("1.2.3.5/32"));
95 +
96 + ip4prefix = new Ip4Prefix("0.0.0.0/0");
97 + assertThat(ip4prefix.toString(), is("0.0.0.0/0"));
98 +
99 + ip4prefix = new Ip4Prefix("255.255.255.255/32");
100 + assertThat(ip4prefix.toString(), is("255.255.255.255/32"));
101 + }
102 +
103 + /**
104 + * Tests invalid class constructor for a null string.
105 + */
106 + @Test(expected = NullPointerException.class)
107 + public void testInvalidConstructorNullString() {
108 + String fromString = null;
109 + Ip4Prefix ip4prefix = new Ip4Prefix(fromString);
110 + }
111 +
112 + /**
113 + * Tests invalid class constructor for an empty string.
114 + */
115 + @Test(expected = IllegalArgumentException.class)
116 + public void testInvalidConstructors() {
117 + // Check constructor for invalid ID: empty string
118 + Ip4Prefix ip4prefix = new Ip4Prefix("");
119 + }
120 +
121 + /**
122 + * Tests getting the value of an address.
123 + */
124 + @Test
125 + public void testGetValue() {
126 + Ip4Prefix ip4prefix = new Ip4Prefix("1.2.3.0/24");
127 + assertThat(ip4prefix.getAddress(), equalTo(new Ip4Address("1.2.3.0")));
128 + assertThat(ip4prefix.getPrefixLen(), is((short) 24));
129 +
130 + ip4prefix = new Ip4Prefix("0.0.0.0/0");
131 + assertThat(ip4prefix.getAddress(), equalTo(new Ip4Address("0.0.0.0")));
132 + assertThat(ip4prefix.getPrefixLen(), is((short) 0));
133 +
134 + ip4prefix = new Ip4Prefix("255.255.255.255/32");
135 + assertThat(ip4prefix.getAddress(),
136 + equalTo(new Ip4Address("255.255.255.255")));
137 + assertThat(ip4prefix.getPrefixLen(), is((short) 32));
138 + }
139 +
140 + /**
141 + * Tests equality of {@link Ip4Address}.
142 + */
143 + @Test
144 + public void testEquality() {
145 + Ip4Prefix addr1net = new Ip4Prefix("1.2.3.0/24");
146 + Ip4Prefix addr2net = new Ip4Prefix("1.2.3.0/24");
147 + assertThat(addr1net, is(addr2net));
148 +
149 + addr1net = new Ip4Prefix("1.2.3.0/24");
150 + addr2net = new Ip4Prefix("1.2.3.4/24");
151 + assertThat(addr1net, is(addr2net));
152 +
153 + addr1net = new Ip4Prefix("0.0.0.0/0");
154 + addr2net = new Ip4Prefix("0.0.0.0/0");
155 + assertThat(addr1net, is(addr2net));
156 +
157 + addr1net = new Ip4Prefix("255.255.255.255/32");
158 + addr2net = new Ip4Prefix("255.255.255.255/32");
159 + assertThat(addr1net, is(addr2net));
160 + }
161 +
162 + /**
163 + * Tests non-equality of {@link Ip4Address}.
164 + */
165 + @Test
166 + public void testNonEquality() {
167 + Ip4Prefix addr1net = new Ip4Prefix("1.2.0.0/16");
168 + Ip4Prefix addr2net = new Ip4Prefix("1.3.0.0/16");
169 + Ip4Prefix addr3net = new Ip4Prefix("1.3.0.0/24");
170 + Ip4Prefix addr4net = new Ip4Prefix("0.0.0.0/0");
171 + Ip4Prefix addr5net = new Ip4Prefix("255.255.255.255/32");
172 + assertThat(addr1net, is(not(addr2net)));
173 + assertThat(addr3net, is(not(addr2net)));
174 + assertThat(addr4net, is(not(addr2net)));
175 + assertThat(addr5net, is(not(addr2net)));
176 + }
177 +
178 + /**
179 + * Tests object string representation.
180 + */
181 + @Test
182 + public void testToString() {
183 + Ip4Prefix ip4prefix = new Ip4Prefix("1.2.3.0/24");
184 + assertThat(ip4prefix.toString(), is("1.2.3.0/24"));
185 +
186 + ip4prefix = new Ip4Prefix("1.2.3.4/24");
187 + assertThat(ip4prefix.toString(), is("1.2.3.0/24"));
188 +
189 + ip4prefix = new Ip4Prefix("0.0.0.0/0");
190 + assertThat(ip4prefix.toString(), is("0.0.0.0/0"));
191 +
192 + ip4prefix = new Ip4Prefix("255.255.255.255/32");
193 + assertThat(ip4prefix.toString(), is("255.255.255.255/32"));
194 + }
195 +}
This diff is collapsed. Click to expand it.
1 +package org.onlab.packet;
2 +
3 +import org.junit.Test;
4 +
5 +import static org.hamcrest.Matchers.equalTo;
6 +import static org.hamcrest.Matchers.is;
7 +import static org.hamcrest.Matchers.not;
8 +import static org.junit.Assert.assertThat;
9 +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
10 +
11 +/**
12 + * Tests for class {@link Ip6Prefix}.
13 + */
14 +public class Ip6PrefixTest {
15 + /**
16 + * Tests the immutability of {@link Ip6Prefix}.
17 + */
18 + @Test
19 + public void testImmutable() {
20 + assertThatClassIsImmutable(Ip6Prefix.class);
21 + }
22 +
23 + /**
24 + * Tests default class constructor.
25 + */
26 + @Test
27 + public void testDefaultConstructor() {
28 + Ip6Prefix ip6prefix = new Ip6Prefix();
29 + assertThat(ip6prefix.toString(), is("::/0"));
30 + }
31 +
32 + /**
33 + * Tests valid class copy constructor.
34 + */
35 + @Test
36 + public void testCopyConstructor() {
37 + Ip6Prefix fromAddr = new Ip6Prefix("1100::/8");
38 + Ip6Prefix ip6prefix = new Ip6Prefix(fromAddr);
39 + assertThat(ip6prefix.toString(), is("1100::/8"));
40 +
41 + fromAddr = new Ip6Prefix("::/0");
42 + ip6prefix = new Ip6Prefix(fromAddr);
43 + assertThat(ip6prefix.toString(), is("::/0"));
44 +
45 + fromAddr =
46 + new Ip6Prefix("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128");
47 + ip6prefix = new Ip6Prefix(fromAddr);
48 + assertThat(ip6prefix.toString(),
49 + is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"));
50 + }
51 +
52 + /**
53 + * Tests invalid class copy constructor for a null object to copy from.
54 + */
55 + @Test(expected = NullPointerException.class)
56 + public void testInvalidConstructorNullObject() {
57 + Ip6Prefix fromAddr = null;
58 + Ip6Prefix ip6prefix = new Ip6Prefix(fromAddr);
59 + }
60 +
61 + /**
62 + * Tests valid class constructor for an address and prefix length.
63 + */
64 + @Test
65 + public void testConstructorForAddressAndPrefixLength() {
66 + Ip6Prefix ip6prefix =
67 + new Ip6Prefix(new Ip6Address("1100::"), (short) 8);
68 + assertThat(ip6prefix.toString(), is("1100::/8"));
69 +
70 + ip6prefix =
71 + new Ip6Prefix(new Ip6Address("1111:2222:3333:4444:5555:6666:7777:8885"),
72 + (short) 8);
73 + assertThat(ip6prefix.toString(), is("1100::/8"));
74 +
75 + ip6prefix =
76 + new Ip6Prefix(new Ip6Address("1111:2222:3333:4444:5555:6666:7777:8800"),
77 + (short) 120);
78 + assertThat(ip6prefix.toString(),
79 + is("1111:2222:3333:4444:5555:6666:7777:8800/120"));
80 +
81 + ip6prefix = new Ip6Prefix(new Ip6Address("::"), (short) 0);
82 + assertThat(ip6prefix.toString(), is("::/0"));
83 +
84 + ip6prefix =
85 + new Ip6Prefix(new Ip6Address("1111:2222:3333:4444:5555:6666:7777:8885"),
86 + (short) 128);
87 + assertThat(ip6prefix.toString(),
88 + is("1111:2222:3333:4444:5555:6666:7777:8885/128"));
89 +
90 + ip6prefix =
91 + new Ip6Prefix(new Ip6Address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"),
92 + (short) 128);
93 + assertThat(ip6prefix.toString(),
94 + is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"));
95 +
96 + ip6prefix =
97 + new Ip6Prefix(new Ip6Address("1111:2222:3333:4444:5555:6666:7777:8885"),
98 + (short) 64);
99 + assertThat(ip6prefix.toString(), is("1111:2222:3333:4444::/64"));
100 + }
101 +
102 + /**
103 + * Tests valid class constructor for a string.
104 + */
105 + @Test
106 + public void testConstructorForString() {
107 + Ip6Prefix ip6prefix = new Ip6Prefix("1100::/8");
108 + assertThat(ip6prefix.toString(), is("1100::/8"));
109 +
110 + ip6prefix = new Ip6Prefix("1111:2222:3333:4444:5555:6666:7777:8885/8");
111 + assertThat(ip6prefix.toString(), is("1100::/8"));
112 +
113 + ip6prefix =
114 + new Ip6Prefix("1111:2222:3333:4444:5555:6666:7777:8800/120");
115 + assertThat(ip6prefix.toString(),
116 + is("1111:2222:3333:4444:5555:6666:7777:8800/120"));
117 +
118 + ip6prefix = new Ip6Prefix("::/0");
119 + assertThat(ip6prefix.toString(), is("::/0"));
120 +
121 + ip6prefix =
122 + new Ip6Prefix("1111:2222:3333:4444:5555:6666:7777:8885/128");
123 + assertThat(ip6prefix.toString(),
124 + is("1111:2222:3333:4444:5555:6666:7777:8885/128"));
125 +
126 + ip6prefix = new Ip6Prefix("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128");
127 + assertThat(ip6prefix.toString(),
128 + is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"));
129 +
130 + ip6prefix =
131 + new Ip6Prefix("1111:2222:3333:4444:5555:6666:7777:8885/64");
132 + assertThat(ip6prefix.toString(), is("1111:2222:3333:4444::/64"));
133 + }
134 +
135 + /**
136 + * Tests invalid class constructor for a null string.
137 + */
138 + @Test(expected = NullPointerException.class)
139 + public void testInvalidConstructorNullString() {
140 + String fromString = null;
141 + Ip6Prefix ip6prefix = new Ip6Prefix(fromString);
142 + }
143 +
144 + /**
145 + * Tests invalid class constructor for an empty string.
146 + */
147 + @Test(expected = IllegalArgumentException.class)
148 + public void testInvalidConstructors() {
149 + // Check constructor for invalid ID: empty string
150 + Ip6Prefix ip6prefix = new Ip6Prefix("");
151 + }
152 +
153 + /**
154 + * Tests getting the value of an address.
155 + */
156 + @Test
157 + public void testGetValue() {
158 + Ip6Prefix ip6prefix = new Ip6Prefix("1100::/8");
159 + assertThat(ip6prefix.getAddress(), equalTo(new Ip6Address("1100::")));
160 + assertThat(ip6prefix.getPrefixLen(), is((short) 8));
161 +
162 + ip6prefix = new Ip6Prefix("1111:2222:3333:4444:5555:6666:7777:8885/8");
163 + assertThat(ip6prefix.getAddress(), equalTo(new Ip6Address("1100::")));
164 + assertThat(ip6prefix.getPrefixLen(), is((short) 8));
165 +
166 + ip6prefix =
167 + new Ip6Prefix("1111:2222:3333:4444:5555:6666:7777:8800/120");
168 + assertThat(ip6prefix.getAddress(),
169 + equalTo(new Ip6Address("1111:2222:3333:4444:5555:6666:7777:8800")));
170 + assertThat(ip6prefix.getPrefixLen(), is((short) 120));
171 +
172 + ip6prefix = new Ip6Prefix("::/0");
173 + assertThat(ip6prefix.getAddress(), equalTo(new Ip6Address("::")));
174 + assertThat(ip6prefix.getPrefixLen(), is((short) 0));
175 +
176 + ip6prefix =
177 + new Ip6Prefix("1111:2222:3333:4444:5555:6666:7777:8885/128");
178 + assertThat(ip6prefix.getAddress(),
179 + equalTo(new Ip6Address("1111:2222:3333:4444:5555:6666:7777:8885")));
180 + assertThat(ip6prefix.getPrefixLen(), is((short) 128));
181 +
182 + ip6prefix =
183 + new Ip6Prefix("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128");
184 + assertThat(ip6prefix.getAddress(),
185 + equalTo(new Ip6Address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));
186 + assertThat(ip6prefix.getPrefixLen(), is((short) 128));
187 +
188 + ip6prefix =
189 + new Ip6Prefix("1111:2222:3333:4444:5555:6666:7777:8885/64");
190 + assertThat(ip6prefix.getAddress(),
191 + equalTo(new Ip6Address("1111:2222:3333:4444::")));
192 + assertThat(ip6prefix.getPrefixLen(), is((short) 64));
193 + }
194 +
195 + /**
196 + * Tests equality of {@link Ip6Address}.
197 + */
198 + @Test
199 + public void testEquality() {
200 + Ip6Prefix addr1net = new Ip6Prefix("1100::/8");
201 + Ip6Prefix addr2net = new Ip6Prefix("1100::/8");
202 + assertThat(addr1net, is(addr2net));
203 +
204 + addr1net = new Ip6Prefix("1111:2222:3333:4444:5555:6666:7777:8885/8");
205 + addr2net = new Ip6Prefix("1100::/8");
206 + assertThat(addr1net, is(addr2net));
207 +
208 + addr1net = new Ip6Prefix("::/0");
209 + addr2net = new Ip6Prefix("::/0");
210 + assertThat(addr1net, is(addr2net));
211 +
212 + addr1net =
213 + new Ip6Prefix("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128");
214 + addr2net =
215 + new Ip6Prefix("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128");
216 + assertThat(addr1net, is(addr2net));
217 + }
218 +
219 + /**
220 + * Tests non-equality of {@link Ip6Address}.
221 + */
222 + @Test
223 + public void testNonEquality() {
224 + Ip6Prefix addr1net = new Ip6Prefix("1100::/8");
225 + Ip6Prefix addr2net = new Ip6Prefix("1200::/8");
226 + Ip6Prefix addr3net = new Ip6Prefix("1200::/12");
227 + Ip6Prefix addr4net = new Ip6Prefix("::/0");
228 + Ip6Prefix addr5net =
229 + new Ip6Prefix("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128");
230 + assertThat(addr1net, is(not(addr2net)));
231 + assertThat(addr3net, is(not(addr2net)));
232 + assertThat(addr4net, is(not(addr2net)));
233 + assertThat(addr5net, is(not(addr2net)));
234 + }
235 +
236 + /**
237 + * Tests object string representation.
238 + */
239 + @Test
240 + public void testToString() {
241 + Ip6Prefix ip6prefix = new Ip6Prefix("1100::/8");
242 + assertThat(ip6prefix.toString(), is("1100::/8"));
243 +
244 + ip6prefix = new Ip6Prefix("1111:2222:3333:4444:5555:6666:7777:8885/8");
245 + assertThat(ip6prefix.toString(), is("1100::/8"));
246 +
247 + ip6prefix = new Ip6Prefix("::/0");
248 + assertThat(ip6prefix.toString(), is("::/0"));
249 +
250 + ip6prefix =
251 + new Ip6Prefix("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128");
252 + assertThat(ip6prefix.toString(),
253 + is("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"));
254 + }
255 +}