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); | ... | ... |
This diff is collapsed. Click to expand it.
| ... | @@ -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.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 | +} |
-
Please register or login to post a comment