Updates for SDN-IP:
* Use the new Leadership Service instead of Distributed Lock to elect the SDN-IP Leader * Reimplement the SDN-IP Intent Synchronizer. In the new implementation the Point-to-Point Peer intents are also synchronized by and pushed only by the Leader (same as the Multipoint-to-SinglePoint Route intents) * Minor cleanups Change-Id: I8e142781211a1d0f2d362875bc28fd05d843cd4b
Showing
11 changed files
with
672 additions
and
358 deletions
| ... | @@ -49,6 +49,12 @@ | ... | @@ -49,6 +49,12 @@ |
| 49 | </dependency> | 49 | </dependency> |
| 50 | 50 | ||
| 51 | <dependency> | 51 | <dependency> |
| 52 | + <groupId>org.apache.commons</groupId> | ||
| 53 | + <artifactId>commons-collections4</artifactId> | ||
| 54 | + <version>4.0</version> | ||
| 55 | + </dependency> | ||
| 56 | + | ||
| 57 | + <dependency> | ||
| 52 | <groupId>org.onlab.onos</groupId> | 58 | <groupId>org.onlab.onos</groupId> |
| 53 | <artifactId>onlab-thirdparty</artifactId> | 59 | <artifactId>onlab-thirdparty</artifactId> |
| 54 | </dependency> | 60 | </dependency> |
| ... | @@ -69,10 +75,12 @@ | ... | @@ -69,10 +75,12 @@ |
| 69 | <artifactId>onos-cli</artifactId> | 75 | <artifactId>onos-cli</artifactId> |
| 70 | <version>${project.version}</version> | 76 | <version>${project.version}</version> |
| 71 | </dependency> | 77 | </dependency> |
| 78 | + | ||
| 72 | <dependency> | 79 | <dependency> |
| 73 | <groupId>org.apache.karaf.shell</groupId> | 80 | <groupId>org.apache.karaf.shell</groupId> |
| 74 | <artifactId>org.apache.karaf.shell.console</artifactId> | 81 | <artifactId>org.apache.karaf.shell.console</artifactId> |
| 75 | </dependency> | 82 | </dependency> |
| 83 | + | ||
| 76 | <dependency> | 84 | <dependency> |
| 77 | <groupId>org.osgi</groupId> | 85 | <groupId>org.osgi</groupId> |
| 78 | <artifactId>org.osgi.core</artifactId> | 86 | <artifactId>org.osgi.core</artifactId> | ... | ... |
| ... | @@ -20,33 +20,37 @@ import java.util.HashMap; | ... | @@ -20,33 +20,37 @@ import java.util.HashMap; |
| 20 | import java.util.LinkedList; | 20 | import java.util.LinkedList; |
| 21 | import java.util.List; | 21 | import java.util.List; |
| 22 | import java.util.Map; | 22 | import java.util.Map; |
| 23 | +import java.util.Objects; | ||
| 23 | import java.util.concurrent.ConcurrentHashMap; | 24 | import java.util.concurrent.ConcurrentHashMap; |
| 24 | import java.util.concurrent.ExecutorService; | 25 | import java.util.concurrent.ExecutorService; |
| 25 | import java.util.concurrent.Executors; | 26 | import java.util.concurrent.Executors; |
| 26 | import java.util.concurrent.Semaphore; | 27 | import java.util.concurrent.Semaphore; |
| 27 | 28 | ||
| 28 | -import org.apache.commons.lang3.tuple.Pair; | ||
| 29 | import org.onlab.onos.core.ApplicationId; | 29 | import org.onlab.onos.core.ApplicationId; |
| 30 | import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion; | 30 | import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion; |
| 31 | import org.onlab.onos.net.flow.criteria.Criterion; | 31 | import org.onlab.onos.net.flow.criteria.Criterion; |
| 32 | import org.onlab.onos.net.intent.Intent; | 32 | import org.onlab.onos.net.intent.Intent; |
| 33 | +import org.onlab.onos.net.intent.IntentOperations; | ||
| 33 | import org.onlab.onos.net.intent.IntentService; | 34 | import org.onlab.onos.net.intent.IntentService; |
| 34 | import org.onlab.onos.net.intent.IntentState; | 35 | import org.onlab.onos.net.intent.IntentState; |
| 35 | import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; | 36 | import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; |
| 37 | +import org.onlab.onos.net.intent.PointToPointIntent; | ||
| 36 | import org.onlab.packet.Ip4Prefix; | 38 | import org.onlab.packet.Ip4Prefix; |
| 37 | import org.slf4j.Logger; | 39 | import org.slf4j.Logger; |
| 38 | import org.slf4j.LoggerFactory; | 40 | import org.slf4j.LoggerFactory; |
| 39 | 41 | ||
| 40 | -import com.google.common.base.Objects; | ||
| 41 | import com.google.common.util.concurrent.ThreadFactoryBuilder; | 42 | import com.google.common.util.concurrent.ThreadFactoryBuilder; |
| 42 | 43 | ||
| 44 | +import static com.google.common.base.Preconditions.checkArgument; | ||
| 45 | + | ||
| 43 | public class IntentSynchronizer { | 46 | public class IntentSynchronizer { |
| 44 | private static final Logger log = | 47 | private static final Logger log = |
| 45 | LoggerFactory.getLogger(IntentSynchronizer.class); | 48 | LoggerFactory.getLogger(IntentSynchronizer.class); |
| 46 | 49 | ||
| 47 | private final ApplicationId appId; | 50 | private final ApplicationId appId; |
| 48 | private final IntentService intentService; | 51 | private final IntentService intentService; |
| 49 | - private final Map<Ip4Prefix, MultiPointToSinglePointIntent> pushedRouteIntents; | 52 | + private final Map<IntentKey, PointToPointIntent> peerIntents; |
| 53 | + private final Map<Ip4Prefix, MultiPointToSinglePointIntent> routeIntents; | ||
| 50 | 54 | ||
| 51 | // | 55 | // |
| 52 | // State to deal with SDN-IP Leader election and pushing Intents | 56 | // State to deal with SDN-IP Leader election and pushing Intents |
| ... | @@ -65,7 +69,8 @@ public class IntentSynchronizer { | ... | @@ -65,7 +69,8 @@ public class IntentSynchronizer { |
| 65 | IntentSynchronizer(ApplicationId appId, IntentService intentService) { | 69 | IntentSynchronizer(ApplicationId appId, IntentService intentService) { |
| 66 | this.appId = appId; | 70 | this.appId = appId; |
| 67 | this.intentService = intentService; | 71 | this.intentService = intentService; |
| 68 | - pushedRouteIntents = new ConcurrentHashMap<>(); | 72 | + peerIntents = new ConcurrentHashMap<>(); |
| 73 | + routeIntents = new ConcurrentHashMap<>(); | ||
| 69 | 74 | ||
| 70 | bgpIntentsSynchronizerExecutor = Executors.newSingleThreadExecutor( | 75 | bgpIntentsSynchronizerExecutor = Executors.newSingleThreadExecutor( |
| 71 | new ThreadFactoryBuilder() | 76 | new ThreadFactoryBuilder() |
| ... | @@ -88,28 +93,47 @@ public class IntentSynchronizer { | ... | @@ -88,28 +93,47 @@ public class IntentSynchronizer { |
| 88 | * Stops the synchronizer. | 93 | * Stops the synchronizer. |
| 89 | */ | 94 | */ |
| 90 | public void stop() { | 95 | public void stop() { |
| 91 | - // Stop the thread(s) | 96 | + synchronized (this) { |
| 92 | - bgpIntentsSynchronizerExecutor.shutdownNow(); | 97 | + // Stop the thread(s) |
| 98 | + bgpIntentsSynchronizerExecutor.shutdownNow(); | ||
| 93 | 99 | ||
| 94 | - // | 100 | + // |
| 95 | - // Withdraw all SDN-IP intents | 101 | + // Withdraw all SDN-IP intents |
| 96 | - // | 102 | + // |
| 97 | - if (!isElectedLeader) { | 103 | + if (!isElectedLeader) { |
| 98 | - return; // Nothing to do: not the leader anymore | 104 | + return; // Nothing to do: not the leader anymore |
| 99 | - } | ||
| 100 | - log.debug("Withdrawing all SDN-IP Route Intents..."); | ||
| 101 | - for (Intent intent : intentService.getIntents()) { | ||
| 102 | - if (!(intent instanceof MultiPointToSinglePointIntent) | ||
| 103 | - || !intent.appId().equals(appId)) { | ||
| 104 | - continue; | ||
| 105 | } | 105 | } |
| 106 | - intentService.withdraw(intent); | ||
| 107 | - } | ||
| 108 | 106 | ||
| 109 | - pushedRouteIntents.clear(); | 107 | + // |
| 108 | + // Build a batch operation to withdraw all intents from this | ||
| 109 | + // application. | ||
| 110 | + // | ||
| 111 | + log.debug("Withdrawing all SDN-IP Intents..."); | ||
| 112 | + IntentOperations.Builder builder = IntentOperations.builder(); | ||
| 113 | + for (Intent intent : intentService.getIntents()) { | ||
| 114 | + // Skip the intents from other applications | ||
| 115 | + if (!intent.appId().equals(appId)) { | ||
| 116 | + continue; | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + // Skip the intents that are already withdrawn | ||
| 120 | + IntentState intentState = | ||
| 121 | + intentService.getIntentState(intent.id()); | ||
| 122 | + if (intentState.equals(IntentState.WITHDRAWING) || | ||
| 123 | + intentState.equals(IntentState.WITHDRAWN)) { | ||
| 124 | + continue; | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + builder.addWithdrawOperation(intent.id()); | ||
| 128 | + } | ||
| 129 | + intentService.execute(builder.build()); | ||
| 130 | + leaderChanged(false); | ||
| 131 | + | ||
| 132 | + peerIntents.clear(); | ||
| 133 | + routeIntents.clear(); | ||
| 134 | + } | ||
| 110 | } | 135 | } |
| 111 | 136 | ||
| 112 | - //@Override TODO hook this up to something | ||
| 113 | public void leaderChanged(boolean isLeader) { | 137 | public void leaderChanged(boolean isLeader) { |
| 114 | log.debug("Leader changed: {}", isLeader); | 138 | log.debug("Leader changed: {}", isLeader); |
| 115 | 139 | ||
| ... | @@ -128,18 +152,18 @@ public class IntentSynchronizer { | ... | @@ -128,18 +152,18 @@ public class IntentSynchronizer { |
| 128 | } | 152 | } |
| 129 | 153 | ||
| 130 | /** | 154 | /** |
| 131 | - * Gets the pushed route intents. | 155 | + * Gets the route intents. |
| 132 | * | 156 | * |
| 133 | - * @return the pushed route intents | 157 | + * @return the route intents |
| 134 | */ | 158 | */ |
| 135 | - public Collection<MultiPointToSinglePointIntent> getPushedRouteIntents() { | 159 | + public Collection<MultiPointToSinglePointIntent> getRouteIntents() { |
| 136 | - List<MultiPointToSinglePointIntent> pushedIntents = new LinkedList<>(); | 160 | + List<MultiPointToSinglePointIntent> result = new LinkedList<>(); |
| 137 | 161 | ||
| 138 | for (Map.Entry<Ip4Prefix, MultiPointToSinglePointIntent> entry : | 162 | for (Map.Entry<Ip4Prefix, MultiPointToSinglePointIntent> entry : |
| 139 | - pushedRouteIntents.entrySet()) { | 163 | + routeIntents.entrySet()) { |
| 140 | - pushedIntents.add(entry.getValue()); | 164 | + result.add(entry.getValue()); |
| 141 | } | 165 | } |
| 142 | - return pushedIntents; | 166 | + return result; |
| 143 | } | 167 | } |
| 144 | 168 | ||
| 145 | /** | 169 | /** |
| ... | @@ -158,11 +182,11 @@ public class IntentSynchronizer { | ... | @@ -158,11 +182,11 @@ public class IntentSynchronizer { |
| 158 | intentsSynchronizerSemaphore.drainPermits(); | 182 | intentsSynchronizerSemaphore.drainPermits(); |
| 159 | } catch (InterruptedException e) { | 183 | } catch (InterruptedException e) { |
| 160 | log.debug("Interrupted while waiting to become " + | 184 | log.debug("Interrupted while waiting to become " + |
| 161 | - "Intent Synchronization leader"); | 185 | + "Intent Synchronization leader"); |
| 162 | interrupted = true; | 186 | interrupted = true; |
| 163 | break; | 187 | break; |
| 164 | } | 188 | } |
| 165 | - syncIntents(); | 189 | + synchronizeIntents(); |
| 166 | } | 190 | } |
| 167 | } finally { | 191 | } finally { |
| 168 | if (interrupted) { | 192 | if (interrupted) { |
| ... | @@ -172,6 +196,29 @@ public class IntentSynchronizer { | ... | @@ -172,6 +196,29 @@ public class IntentSynchronizer { |
| 172 | } | 196 | } |
| 173 | 197 | ||
| 174 | /** | 198 | /** |
| 199 | + * Submits a collection of point-to-point intents. | ||
| 200 | + * | ||
| 201 | + * @param intents the intents to submit | ||
| 202 | + */ | ||
| 203 | + void submitPeerIntents(Collection<PointToPointIntent> intents) { | ||
| 204 | + synchronized (this) { | ||
| 205 | + // Store the intents in memory | ||
| 206 | + for (PointToPointIntent intent : intents) { | ||
| 207 | + peerIntents.put(new IntentKey(intent), intent); | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + // Push the intents | ||
| 211 | + if (isElectedLeader && isActivatedLeader) { | ||
| 212 | + log.debug("Submitting all SDN-IP Peer Intents..."); | ||
| 213 | + // TODO: We should use a single Intent batch operation | ||
| 214 | + for (Intent intent : intents) { | ||
| 215 | + intentService.submit(intent); | ||
| 216 | + } | ||
| 217 | + } | ||
| 218 | + } | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + /** | ||
| 175 | * Submits a multi-point-to-single-point intent. | 222 | * Submits a multi-point-to-single-point intent. |
| 176 | * | 223 | * |
| 177 | * @param prefix the IPv4 matching prefix for the intent to submit | 224 | * @param prefix the IPv4 matching prefix for the intent to submit |
| ... | @@ -180,14 +227,21 @@ public class IntentSynchronizer { | ... | @@ -180,14 +227,21 @@ public class IntentSynchronizer { |
| 180 | void submitRouteIntent(Ip4Prefix prefix, | 227 | void submitRouteIntent(Ip4Prefix prefix, |
| 181 | MultiPointToSinglePointIntent intent) { | 228 | MultiPointToSinglePointIntent intent) { |
| 182 | synchronized (this) { | 229 | synchronized (this) { |
| 230 | + MultiPointToSinglePointIntent oldIntent = | ||
| 231 | + routeIntents.put(prefix, intent); | ||
| 232 | + | ||
| 183 | if (isElectedLeader && isActivatedLeader) { | 233 | if (isElectedLeader && isActivatedLeader) { |
| 184 | log.debug("Intent installation: adding Intent for prefix: {}", | 234 | log.debug("Intent installation: adding Intent for prefix: {}", |
| 185 | prefix); | 235 | prefix); |
| 236 | + if (oldIntent != null) { | ||
| 237 | + // | ||
| 238 | + // TODO: Short-term solution to explicitly withdraw | ||
| 239 | + // instead of using "replace" operation. | ||
| 240 | + // | ||
| 241 | + intentService.withdraw(oldIntent); | ||
| 242 | + } | ||
| 186 | intentService.submit(intent); | 243 | intentService.submit(intent); |
| 187 | } | 244 | } |
| 188 | - | ||
| 189 | - // Maintain the Intent | ||
| 190 | - pushedRouteIntents.put(prefix, intent); | ||
| 191 | } | 245 | } |
| 192 | } | 246 | } |
| 193 | 247 | ||
| ... | @@ -199,11 +253,11 @@ public class IntentSynchronizer { | ... | @@ -199,11 +253,11 @@ public class IntentSynchronizer { |
| 199 | void withdrawRouteIntent(Ip4Prefix prefix) { | 253 | void withdrawRouteIntent(Ip4Prefix prefix) { |
| 200 | synchronized (this) { | 254 | synchronized (this) { |
| 201 | MultiPointToSinglePointIntent intent = | 255 | MultiPointToSinglePointIntent intent = |
| 202 | - pushedRouteIntents.remove(prefix); | 256 | + routeIntents.remove(prefix); |
| 203 | 257 | ||
| 204 | if (intent == null) { | 258 | if (intent == null) { |
| 205 | - log.debug("There is no intent in pushedRouteIntents to delete " + | 259 | + log.debug("There is no Intent in routeIntents to " + |
| 206 | - "for prefix: {}", prefix); | 260 | + "delete for prefix: {}", prefix); |
| 207 | return; | 261 | return; |
| 208 | } | 262 | } |
| 209 | 263 | ||
| ... | @@ -216,191 +270,312 @@ public class IntentSynchronizer { | ... | @@ -216,191 +270,312 @@ public class IntentSynchronizer { |
| 216 | } | 270 | } |
| 217 | 271 | ||
| 218 | /** | 272 | /** |
| 219 | - * Performs Intents Synchronization between the internally stored Route | 273 | + * Synchronize the in-memory Intents with the Intents in the Intent |
| 220 | - * Intents and the installed Route Intents. | 274 | + * framework. |
| 221 | */ | 275 | */ |
| 222 | - private void syncIntents() { | 276 | + void synchronizeIntents() { |
| 223 | synchronized (this) { | 277 | synchronized (this) { |
| 278 | + | ||
| 279 | + Map<IntentKey, Intent> localIntents = new HashMap<>(); | ||
| 280 | + Map<IntentKey, Intent> fetchedIntents = new HashMap<>(); | ||
| 281 | + Collection<Intent> storeInMemoryIntents = new LinkedList<>(); | ||
| 282 | + Collection<Intent> addIntents = new LinkedList<>(); | ||
| 283 | + Collection<Intent> deleteIntents = new LinkedList<>(); | ||
| 284 | + | ||
| 224 | if (!isElectedLeader) { | 285 | if (!isElectedLeader) { |
| 225 | return; // Nothing to do: not the leader anymore | 286 | return; // Nothing to do: not the leader anymore |
| 226 | } | 287 | } |
| 227 | - log.debug("Syncing SDN-IP Route Intents..."); | 288 | + log.debug("Syncing SDN-IP Intents..."); |
| 228 | 289 | ||
| 229 | - Map<Ip4Prefix, MultiPointToSinglePointIntent> fetchedIntents = | 290 | + // Prepare the local intents |
| 230 | - new HashMap<>(); | 291 | + for (Intent intent : routeIntents.values()) { |
| 292 | + localIntents.put(new IntentKey(intent), intent); | ||
| 293 | + } | ||
| 294 | + for (Intent intent : peerIntents.values()) { | ||
| 295 | + localIntents.put(new IntentKey(intent), intent); | ||
| 296 | + } | ||
| 231 | 297 | ||
| 232 | - // | 298 | + // Fetch all intents for this application |
| 233 | - // Fetch all intents, and classify the Multi-Point-to-Point Intents | ||
| 234 | - // based on the matching prefix. | ||
| 235 | - // | ||
| 236 | for (Intent intent : intentService.getIntents()) { | 299 | for (Intent intent : intentService.getIntents()) { |
| 237 | - | 300 | + if (!intent.appId().equals(appId)) { |
| 238 | - if (!(intent instanceof MultiPointToSinglePointIntent) | ||
| 239 | - || !intent.appId().equals(appId)) { | ||
| 240 | continue; | 301 | continue; |
| 241 | } | 302 | } |
| 242 | - MultiPointToSinglePointIntent mp2pIntent = | 303 | + fetchedIntents.put(new IntentKey(intent), intent); |
| 243 | - (MultiPointToSinglePointIntent) intent; | ||
| 244 | - | ||
| 245 | - Criterion c = | ||
| 246 | - mp2pIntent.selector().getCriterion(Criterion.Type.IPV4_DST); | ||
| 247 | - if (c != null && c instanceof IPCriterion) { | ||
| 248 | - IPCriterion ipCriterion = (IPCriterion) c; | ||
| 249 | - Ip4Prefix ip4Prefix = ipCriterion.ip().getIp4Prefix(); | ||
| 250 | - if (ip4Prefix == null) { | ||
| 251 | - // TODO: For now we support only IPv4 | ||
| 252 | - continue; | ||
| 253 | - } | ||
| 254 | - fetchedIntents.put(ip4Prefix, mp2pIntent); | ||
| 255 | - } else { | ||
| 256 | - log.warn("No IPV4_DST criterion found for intent {}", | ||
| 257 | - mp2pIntent.id()); | ||
| 258 | - } | ||
| 259 | - | ||
| 260 | } | 304 | } |
| 261 | 305 | ||
| 306 | + computeIntentsDelta(localIntents, fetchedIntents, | ||
| 307 | + storeInMemoryIntents, addIntents, | ||
| 308 | + deleteIntents); | ||
| 309 | + | ||
| 262 | // | 310 | // |
| 263 | - // Compare for each prefix the local IN-MEMORY Intents with the | 311 | + // Perform the actions: |
| 264 | - // FETCHED Intents: | 312 | + // 1. Store in memory fetched intents that are same. Can be done |
| 265 | - // - If the IN-MEMORY Intent is same as the FETCHED Intent, store | 313 | + // even if we are not the leader anymore |
| 266 | - // the FETCHED Intent in the local memory (i.e., override the | 314 | + // 2. Delete intents: check if the leader before the operation |
| 267 | - // IN-MEMORY Intent) to preserve the original Intent ID | 315 | + // 3. Add intents: check if the leader before the operation |
| 268 | - // - if the IN-MEMORY Intent is not same as the FETCHED Intent, | ||
| 269 | - // delete the FETCHED Intent, and push/install the IN-MEMORY | ||
| 270 | - // Intent. | ||
| 271 | - // - If there is an IN-MEMORY Intent for a prefix, but no FETCHED | ||
| 272 | - // Intent for same prefix, then push/install the IN-MEMORY | ||
| 273 | - // Intent. | ||
| 274 | - // - If there is a FETCHED Intent for a prefix, but no IN-MEMORY | ||
| 275 | - // Intent for same prefix, then delete/withdraw the FETCHED | ||
| 276 | - // Intent. | ||
| 277 | // | 316 | // |
| 278 | - Collection<Pair<Ip4Prefix, MultiPointToSinglePointIntent>> | 317 | + for (Intent intent : storeInMemoryIntents) { |
| 279 | - storeInMemoryIntents = new LinkedList<>(); | 318 | + // Store the intent in memory based on its type |
| 280 | - Collection<Pair<Ip4Prefix, MultiPointToSinglePointIntent>> | 319 | + if (intent instanceof MultiPointToSinglePointIntent) { |
| 281 | - addIntents = new LinkedList<>(); | 320 | + MultiPointToSinglePointIntent mp2pIntent = |
| 282 | - Collection<Pair<Ip4Prefix, MultiPointToSinglePointIntent>> | 321 | + (MultiPointToSinglePointIntent) intent; |
| 283 | - deleteIntents = new LinkedList<>(); | 322 | + // Find the IP prefix |
| 284 | - for (Map.Entry<Ip4Prefix, MultiPointToSinglePointIntent> entry : | 323 | + Criterion c = |
| 285 | - pushedRouteIntents.entrySet()) { | 324 | + mp2pIntent.selector().getCriterion(Criterion.Type.IPV4_DST); |
| 286 | - Ip4Prefix prefix = entry.getKey(); | 325 | + if (c != null && c instanceof IPCriterion) { |
| 287 | - MultiPointToSinglePointIntent inMemoryIntent = | 326 | + IPCriterion ipCriterion = (IPCriterion) c; |
| 288 | - entry.getValue(); | 327 | + Ip4Prefix ip4Prefix = ipCriterion.ip().getIp4Prefix(); |
| 289 | - MultiPointToSinglePointIntent fetchedIntent = | 328 | + if (ip4Prefix == null) { |
| 290 | - fetchedIntents.get(prefix); | 329 | + // TODO: For now we support only IPv4 |
| 291 | - | 330 | + continue; |
| 292 | - if (fetchedIntent == null) { | 331 | + } |
| 293 | - // | 332 | + log.debug("Intent synchronization: updating " + |
| 294 | - // No FETCHED Intent for same prefix: push the IN-MEMORY | 333 | + "in-memory Route Intent for prefix {}", |
| 295 | - // Intent. | 334 | + ip4Prefix); |
| 296 | - // | 335 | + routeIntents.put(ip4Prefix, mp2pIntent); |
| 297 | - addIntents.add(Pair.of(prefix, inMemoryIntent)); | 336 | + } else { |
| 337 | + log.warn("No IPV4_DST criterion found for Intent {}", | ||
| 338 | + mp2pIntent.id()); | ||
| 339 | + } | ||
| 298 | continue; | 340 | continue; |
| 299 | } | 341 | } |
| 300 | - | 342 | + if (intent instanceof PointToPointIntent) { |
| 301 | - IntentState state = intentService.getIntentState(fetchedIntent.id()); | 343 | + PointToPointIntent p2pIntent = (PointToPointIntent) intent; |
| 302 | - if (state == IntentState.WITHDRAWING || | 344 | + log.debug("Intent synchronization: updating " + |
| 303 | - state == IntentState.WITHDRAWN) { | 345 | + "in-memory Peer Intent {}", p2pIntent); |
| 304 | - // The intent has been withdrawn but according to our route | 346 | + peerIntents.put(new IntentKey(intent), p2pIntent); |
| 305 | - // table it should be installed. We'll reinstall it. | 347 | + continue; |
| 306 | - addIntents.add(Pair.of(prefix, inMemoryIntent)); | ||
| 307 | - } | ||
| 308 | - | ||
| 309 | - // | ||
| 310 | - // If IN-MEMORY Intent is same as the FETCHED Intent, | ||
| 311 | - // store the FETCHED Intent in the local memory. | ||
| 312 | - // | ||
| 313 | - if (compareMultiPointToSinglePointIntents(inMemoryIntent, | ||
| 314 | - fetchedIntent)) { | ||
| 315 | - storeInMemoryIntents.add(Pair.of(prefix, fetchedIntent)); | ||
| 316 | - } else { | ||
| 317 | - // | ||
| 318 | - // The IN-MEMORY Intent is not same as the FETCHED Intent, | ||
| 319 | - // hence delete the FETCHED Intent, and install the | ||
| 320 | - // IN-MEMORY Intent. | ||
| 321 | - // | ||
| 322 | - deleteIntents.add(Pair.of(prefix, fetchedIntent)); | ||
| 323 | - addIntents.add(Pair.of(prefix, inMemoryIntent)); | ||
| 324 | } | 348 | } |
| 325 | - fetchedIntents.remove(prefix); | ||
| 326 | } | 349 | } |
| 327 | 350 | ||
| 328 | - // | 351 | + // Withdraw Intents |
| 329 | - // Any remaining FETCHED Intents have to be deleted/withdrawn | 352 | + IntentOperations.Builder builder = IntentOperations.builder(); |
| 330 | - // | 353 | + for (Intent intent : deleteIntents) { |
| 331 | - for (Map.Entry<Ip4Prefix, MultiPointToSinglePointIntent> entry : | 354 | + builder.addWithdrawOperation(intent.id()); |
| 332 | - fetchedIntents.entrySet()) { | 355 | + log.debug("Intent synchronization: deleting Intent {}", |
| 333 | - Ip4Prefix prefix = entry.getKey(); | 356 | + intent); |
| 334 | - MultiPointToSinglePointIntent fetchedIntent = entry.getValue(); | ||
| 335 | - deleteIntents.add(Pair.of(prefix, fetchedIntent)); | ||
| 336 | - } | ||
| 337 | - | ||
| 338 | - // | ||
| 339 | - // Perform the actions: | ||
| 340 | - // 1. Store in memory fetched intents that are same. Can be done | ||
| 341 | - // even if we are not the leader anymore | ||
| 342 | - // 2. Delete intents: check if the leader before each operation | ||
| 343 | - // 3. Add intents: check if the leader before each operation | ||
| 344 | - // | ||
| 345 | - for (Pair<Ip4Prefix, MultiPointToSinglePointIntent> pair : | ||
| 346 | - storeInMemoryIntents) { | ||
| 347 | - Ip4Prefix prefix = pair.getLeft(); | ||
| 348 | - MultiPointToSinglePointIntent intent = pair.getRight(); | ||
| 349 | - log.debug("Intent synchronization: updating in-memory " + | ||
| 350 | - "Intent for prefix: {}", prefix); | ||
| 351 | - pushedRouteIntents.put(prefix, intent); | ||
| 352 | } | 357 | } |
| 353 | - // | 358 | + if (!isElectedLeader) { |
| 354 | - isActivatedLeader = true; // Allow push of Intents | 359 | + isActivatedLeader = false; |
| 355 | - for (Pair<Ip4Prefix, MultiPointToSinglePointIntent> pair : | 360 | + return; |
| 356 | - deleteIntents) { | ||
| 357 | - Ip4Prefix prefix = pair.getLeft(); | ||
| 358 | - MultiPointToSinglePointIntent intent = pair.getRight(); | ||
| 359 | - if (!isElectedLeader) { | ||
| 360 | - isActivatedLeader = false; | ||
| 361 | - return; | ||
| 362 | - } | ||
| 363 | - log.debug("Intent synchronization: deleting Intent for " + | ||
| 364 | - "prefix: {}", prefix); | ||
| 365 | - intentService.withdraw(intent); | ||
| 366 | } | 361 | } |
| 367 | - // | 362 | + intentService.execute(builder.build()); |
| 368 | - for (Pair<Ip4Prefix, MultiPointToSinglePointIntent> pair : | 363 | + |
| 369 | - addIntents) { | 364 | + // Add Intents |
| 370 | - Ip4Prefix prefix = pair.getLeft(); | 365 | + builder = IntentOperations.builder(); |
| 371 | - MultiPointToSinglePointIntent intent = pair.getRight(); | 366 | + for (Intent intent : addIntents) { |
| 372 | - if (!isElectedLeader) { | 367 | + builder.addSubmitOperation(intent); |
| 373 | - isActivatedLeader = false; | 368 | + log.debug("Intent synchronization: adding Intent {}", intent); |
| 374 | - return; | ||
| 375 | - } | ||
| 376 | - log.debug("Intent synchronization: adding Intent for " + | ||
| 377 | - "prefix: {}", prefix); | ||
| 378 | - intentService.submit(intent); | ||
| 379 | } | 369 | } |
| 380 | if (!isElectedLeader) { | 370 | if (!isElectedLeader) { |
| 381 | isActivatedLeader = false; | 371 | isActivatedLeader = false; |
| 372 | + return; | ||
| 373 | + } | ||
| 374 | + intentService.execute(builder.build()); | ||
| 375 | + | ||
| 376 | + if (isElectedLeader) { | ||
| 377 | + isActivatedLeader = true; // Allow push of Intents | ||
| 378 | + } else { | ||
| 379 | + isActivatedLeader = false; | ||
| 382 | } | 380 | } |
| 383 | log.debug("Syncing SDN-IP routes completed."); | 381 | log.debug("Syncing SDN-IP routes completed."); |
| 384 | } | 382 | } |
| 385 | } | 383 | } |
| 386 | 384 | ||
| 387 | /** | 385 | /** |
| 388 | - * Compares two Multi-point to Single Point Intents whether they represent | 386 | + * Computes the delta in two sets of Intents: local in-memory Intents, |
| 389 | - * same logical intention. | 387 | + * and intents fetched from the Intent framework. |
| 390 | * | 388 | * |
| 391 | - * @param intent1 the first Intent to compare | 389 | + * @param localIntents the local in-memory Intents |
| 392 | - * @param intent2 the second Intent to compare | 390 | + * @param fetchedIntents the Intents fetched from the Intent framework |
| 393 | - * @return true if both Intents represent same logical intention, otherwise | 391 | + * @param storeInMemoryIntents the Intents that should be stored in memory. |
| 394 | - * false | 392 | + * Note: This Collection must be allocated by the caller, and it will |
| 393 | + * be populated by this method. | ||
| 394 | + * @param addIntents the Intents that should be added to the Intent | ||
| 395 | + * framework. Note: This Collection must be allocated by the caller, and | ||
| 396 | + * it will be populated by this method. | ||
| 397 | + * @param deleteIntents the Intents that should be deleted from the Intent | ||
| 398 | + * framework. Note: This Collection must be allocated by the caller, and | ||
| 399 | + * it will be populated by this method. | ||
| 395 | */ | 400 | */ |
| 396 | - private boolean compareMultiPointToSinglePointIntents( | 401 | + private void computeIntentsDelta( |
| 397 | - MultiPointToSinglePointIntent intent1, | 402 | + final Map<IntentKey, Intent> localIntents, |
| 398 | - MultiPointToSinglePointIntent intent2) { | 403 | + final Map<IntentKey, Intent> fetchedIntents, |
| 399 | - | 404 | + Collection<Intent> storeInMemoryIntents, |
| 400 | - return Objects.equal(intent1.appId(), intent2.appId()) && | 405 | + Collection<Intent> addIntents, |
| 401 | - Objects.equal(intent1.selector(), intent2.selector()) && | 406 | + Collection<Intent> deleteIntents) { |
| 402 | - Objects.equal(intent1.treatment(), intent2.treatment()) && | 407 | + |
| 403 | - Objects.equal(intent1.ingressPoints(), intent2.ingressPoints()) && | 408 | + // |
| 404 | - Objects.equal(intent1.egressPoint(), intent2.egressPoint()); | 409 | + // Compute the deltas between the LOCAL in-memory Intents and the |
| 410 | + // FETCHED Intents: | ||
| 411 | + // - If an Intent is in both the LOCAL and FETCHED sets: | ||
| 412 | + // If the FETCHED Intent is WITHDRAWING or WITHDRAWN, then | ||
| 413 | + // the LOCAL Intent should be added/installed; otherwise the | ||
| 414 | + // FETCHED intent should be stored in the local memory | ||
| 415 | + // (i.e., override the LOCAL Intent) to preserve the original | ||
| 416 | + // Intent ID. | ||
| 417 | + // - if a LOCAL Intent is not in the FETCHED set, then the LOCAL | ||
| 418 | + // Intent should be added/installed. | ||
| 419 | + // - If a FETCHED Intent is not in the LOCAL set, then the FETCHED | ||
| 420 | + // Intent should be deleted/withdrawn. | ||
| 421 | + // | ||
| 422 | + for (Map.Entry<IntentKey, Intent> entry : localIntents.entrySet()) { | ||
| 423 | + IntentKey intentKey = entry.getKey(); | ||
| 424 | + Intent localIntent = entry.getValue(); | ||
| 425 | + Intent fetchedIntent = fetchedIntents.get(intentKey); | ||
| 426 | + | ||
| 427 | + if (fetchedIntent == null) { | ||
| 428 | + // | ||
| 429 | + // No FETCHED Intent found: push the LOCAL Intent. | ||
| 430 | + // | ||
| 431 | + addIntents.add(localIntent); | ||
| 432 | + continue; | ||
| 433 | + } | ||
| 434 | + | ||
| 435 | + IntentState state = | ||
| 436 | + intentService.getIntentState(fetchedIntent.id()); | ||
| 437 | + if (state == IntentState.WITHDRAWING || | ||
| 438 | + state == IntentState.WITHDRAWN) { | ||
| 439 | + // The intent has been withdrawn but according to our route | ||
| 440 | + // table it should be installed. We'll reinstall it. | ||
| 441 | + addIntents.add(localIntent); | ||
| 442 | + continue; | ||
| 443 | + } | ||
| 444 | + storeInMemoryIntents.add(fetchedIntent); | ||
| 445 | + } | ||
| 446 | + | ||
| 447 | + for (Map.Entry<IntentKey, Intent> entry : fetchedIntents.entrySet()) { | ||
| 448 | + IntentKey intentKey = entry.getKey(); | ||
| 449 | + Intent fetchedIntent = entry.getValue(); | ||
| 450 | + Intent localIntent = localIntents.get(intentKey); | ||
| 451 | + | ||
| 452 | + if (localIntent != null) { | ||
| 453 | + continue; | ||
| 454 | + } | ||
| 455 | + | ||
| 456 | + IntentState state = | ||
| 457 | + intentService.getIntentState(fetchedIntent.id()); | ||
| 458 | + if (state == IntentState.WITHDRAWING || | ||
| 459 | + state == IntentState.WITHDRAWN) { | ||
| 460 | + // Nothing to do. The intent has been already withdrawn. | ||
| 461 | + continue; | ||
| 462 | + } | ||
| 463 | + // | ||
| 464 | + // No LOCAL Intent found: delete/withdraw the FETCHED Intent. | ||
| 465 | + // | ||
| 466 | + deleteIntents.add(fetchedIntent); | ||
| 467 | + } | ||
| 468 | + } | ||
| 469 | + | ||
| 470 | + /** | ||
| 471 | + * Helper class that can be used to compute the key for an Intent by | ||
| 472 | + * by excluding the Intent ID. | ||
| 473 | + */ | ||
| 474 | + static final class IntentKey { | ||
| 475 | + private final Intent intent; | ||
| 476 | + | ||
| 477 | + /** | ||
| 478 | + * Constructor. | ||
| 479 | + * | ||
| 480 | + * @param intent the intent to use | ||
| 481 | + */ | ||
| 482 | + IntentKey(Intent intent) { | ||
| 483 | + checkArgument((intent instanceof MultiPointToSinglePointIntent) || | ||
| 484 | + (intent instanceof PointToPointIntent), | ||
| 485 | + "Intent type not recognized", intent); | ||
| 486 | + this.intent = intent; | ||
| 487 | + } | ||
| 488 | + | ||
| 489 | + /** | ||
| 490 | + * Compares two Multi-Point to Single-Point Intents whether they | ||
| 491 | + * represent same logical intention. | ||
| 492 | + * | ||
| 493 | + * @param intent1 the first Intent to compare | ||
| 494 | + * @param intent2 the second Intent to compare | ||
| 495 | + * @return true if both Intents represent same logical intention, | ||
| 496 | + * otherwise false | ||
| 497 | + */ | ||
| 498 | + static boolean equalIntents(MultiPointToSinglePointIntent intent1, | ||
| 499 | + MultiPointToSinglePointIntent intent2) { | ||
| 500 | + return Objects.equals(intent1.appId(), intent2.appId()) && | ||
| 501 | + Objects.equals(intent1.selector(), intent2.selector()) && | ||
| 502 | + Objects.equals(intent1.treatment(), intent2.treatment()) && | ||
| 503 | + Objects.equals(intent1.ingressPoints(), intent2.ingressPoints()) && | ||
| 504 | + Objects.equals(intent1.egressPoint(), intent2.egressPoint()); | ||
| 505 | + } | ||
| 506 | + | ||
| 507 | + /** | ||
| 508 | + * Compares two Point-to-Point Intents whether they represent | ||
| 509 | + * same logical intention. | ||
| 510 | + * | ||
| 511 | + * @param intent1 the first Intent to compare | ||
| 512 | + * @param intent2 the second Intent to compare | ||
| 513 | + * @return true if both Intents represent same logical intention, | ||
| 514 | + * otherwise false | ||
| 515 | + */ | ||
| 516 | + static boolean equalIntents(PointToPointIntent intent1, | ||
| 517 | + PointToPointIntent intent2) { | ||
| 518 | + return Objects.equals(intent1.appId(), intent2.appId()) && | ||
| 519 | + Objects.equals(intent1.selector(), intent2.selector()) && | ||
| 520 | + Objects.equals(intent1.treatment(), intent2.treatment()) && | ||
| 521 | + Objects.equals(intent1.ingressPoint(), intent2.ingressPoint()) && | ||
| 522 | + Objects.equals(intent1.egressPoint(), intent2.egressPoint()); | ||
| 523 | + } | ||
| 524 | + | ||
| 525 | + @Override | ||
| 526 | + public int hashCode() { | ||
| 527 | + if (intent instanceof PointToPointIntent) { | ||
| 528 | + PointToPointIntent p2pIntent = (PointToPointIntent) intent; | ||
| 529 | + return Objects.hash(p2pIntent.appId(), | ||
| 530 | + p2pIntent.resources(), | ||
| 531 | + p2pIntent.selector(), | ||
| 532 | + p2pIntent.treatment(), | ||
| 533 | + p2pIntent.constraints(), | ||
| 534 | + p2pIntent.ingressPoint(), | ||
| 535 | + p2pIntent.egressPoint()); | ||
| 536 | + } | ||
| 537 | + if (intent instanceof MultiPointToSinglePointIntent) { | ||
| 538 | + MultiPointToSinglePointIntent m2pIntent = | ||
| 539 | + (MultiPointToSinglePointIntent) intent; | ||
| 540 | + return Objects.hash(m2pIntent.appId(), | ||
| 541 | + m2pIntent.resources(), | ||
| 542 | + m2pIntent.selector(), | ||
| 543 | + m2pIntent.treatment(), | ||
| 544 | + m2pIntent.constraints(), | ||
| 545 | + m2pIntent.ingressPoints(), | ||
| 546 | + m2pIntent.egressPoint()); | ||
| 547 | + } | ||
| 548 | + checkArgument(false, "Intent type not recognized", intent); | ||
| 549 | + return 0; | ||
| 550 | + } | ||
| 551 | + | ||
| 552 | + @Override | ||
| 553 | + public boolean equals(Object obj) { | ||
| 554 | + if (this == obj) { | ||
| 555 | + return true; | ||
| 556 | + } | ||
| 557 | + if ((obj == null) || (!(obj instanceof IntentKey))) { | ||
| 558 | + return false; | ||
| 559 | + } | ||
| 560 | + IntentKey other = (IntentKey) obj; | ||
| 561 | + | ||
| 562 | + if (this.intent instanceof PointToPointIntent) { | ||
| 563 | + if (!(other.intent instanceof PointToPointIntent)) { | ||
| 564 | + return false; | ||
| 565 | + } | ||
| 566 | + return equalIntents((PointToPointIntent) this.intent, | ||
| 567 | + (PointToPointIntent) other.intent); | ||
| 568 | + } | ||
| 569 | + if (this.intent instanceof MultiPointToSinglePointIntent) { | ||
| 570 | + if (!(other.intent instanceof MultiPointToSinglePointIntent)) { | ||
| 571 | + return false; | ||
| 572 | + } | ||
| 573 | + return equalIntents( | ||
| 574 | + (MultiPointToSinglePointIntent) this.intent, | ||
| 575 | + (MultiPointToSinglePointIntent) other.intent); | ||
| 576 | + } | ||
| 577 | + checkArgument(false, "Intent type not recognized", intent); | ||
| 578 | + return false; | ||
| 579 | + } | ||
| 405 | } | 580 | } |
| 406 | } | 581 | } | ... | ... |
| ... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
| 16 | package org.onlab.onos.sdnip; | 16 | package org.onlab.onos.sdnip; |
| 17 | 17 | ||
| 18 | import java.util.ArrayList; | 18 | import java.util.ArrayList; |
| 19 | +import java.util.Collection; | ||
| 19 | import java.util.List; | 20 | import java.util.List; |
| 20 | 21 | ||
| 21 | import org.onlab.onos.core.ApplicationId; | 22 | import org.onlab.onos.core.ApplicationId; |
| ... | @@ -24,8 +25,6 @@ import org.onlab.onos.net.flow.DefaultTrafficSelector; | ... | @@ -24,8 +25,6 @@ import org.onlab.onos.net.flow.DefaultTrafficSelector; |
| 24 | import org.onlab.onos.net.flow.DefaultTrafficTreatment; | 25 | import org.onlab.onos.net.flow.DefaultTrafficTreatment; |
| 25 | import org.onlab.onos.net.flow.TrafficSelector; | 26 | import org.onlab.onos.net.flow.TrafficSelector; |
| 26 | import org.onlab.onos.net.flow.TrafficTreatment; | 27 | import org.onlab.onos.net.flow.TrafficTreatment; |
| 27 | -import org.onlab.onos.net.intent.Intent; | ||
| 28 | -import org.onlab.onos.net.intent.IntentService; | ||
| 29 | import org.onlab.onos.net.intent.PointToPointIntent; | 28 | import org.onlab.onos.net.intent.PointToPointIntent; |
| 30 | import org.onlab.onos.sdnip.bgp.BgpConstants; | 29 | import org.onlab.onos.sdnip.bgp.BgpConstants; |
| 31 | import org.onlab.onos.sdnip.config.BgpPeer; | 30 | import org.onlab.onos.sdnip.config.BgpPeer; |
| ... | @@ -48,9 +47,9 @@ public class PeerConnectivityManager { | ... | @@ -48,9 +47,9 @@ public class PeerConnectivityManager { |
| 48 | private static final Logger log = LoggerFactory.getLogger( | 47 | private static final Logger log = LoggerFactory.getLogger( |
| 49 | PeerConnectivityManager.class); | 48 | PeerConnectivityManager.class); |
| 50 | 49 | ||
| 50 | + private final IntentSynchronizer intentSynchronizer; | ||
| 51 | private final SdnIpConfigService configService; | 51 | private final SdnIpConfigService configService; |
| 52 | private final InterfaceService interfaceService; | 52 | private final InterfaceService interfaceService; |
| 53 | - private final IntentService intentService; | ||
| 54 | 53 | ||
| 55 | private final ApplicationId appId; | 54 | private final ApplicationId appId; |
| 56 | 55 | ||
| ... | @@ -58,18 +57,18 @@ public class PeerConnectivityManager { | ... | @@ -58,18 +57,18 @@ public class PeerConnectivityManager { |
| 58 | * Creates a new PeerConnectivityManager. | 57 | * Creates a new PeerConnectivityManager. |
| 59 | * | 58 | * |
| 60 | * @param appId the application ID | 59 | * @param appId the application ID |
| 60 | + * @param intentSynchronizer the intent synchronizer | ||
| 61 | * @param configService the SDN-IP config service | 61 | * @param configService the SDN-IP config service |
| 62 | * @param interfaceService the interface service | 62 | * @param interfaceService the interface service |
| 63 | - * @param intentService the intent service | ||
| 64 | */ | 63 | */ |
| 65 | public PeerConnectivityManager(ApplicationId appId, | 64 | public PeerConnectivityManager(ApplicationId appId, |
| 65 | + IntentSynchronizer intentSynchronizer, | ||
| 66 | SdnIpConfigService configService, | 66 | SdnIpConfigService configService, |
| 67 | - InterfaceService interfaceService, | 67 | + InterfaceService interfaceService) { |
| 68 | - IntentService intentService) { | ||
| 69 | this.appId = appId; | 68 | this.appId = appId; |
| 69 | + this.intentSynchronizer = intentSynchronizer; | ||
| 70 | this.configService = configService; | 70 | this.configService = configService; |
| 71 | this.interfaceService = interfaceService; | 71 | this.interfaceService = interfaceService; |
| 72 | - this.intentService = intentService; | ||
| 73 | } | 72 | } |
| 74 | 73 | ||
| 75 | /** | 74 | /** |
| ... | @@ -107,6 +106,8 @@ public class PeerConnectivityManager { | ... | @@ -107,6 +106,8 @@ public class PeerConnectivityManager { |
| 107 | * {@link BgpSpeaker}s and all external {@link BgpPeer}s. | 106 | * {@link BgpSpeaker}s and all external {@link BgpPeer}s. |
| 108 | */ | 107 | */ |
| 109 | private void setUpConnectivity() { | 108 | private void setUpConnectivity() { |
| 109 | + List<PointToPointIntent> intents = new ArrayList<>(); | ||
| 110 | + | ||
| 110 | for (BgpSpeaker bgpSpeaker : configService.getBgpSpeakers() | 111 | for (BgpSpeaker bgpSpeaker : configService.getBgpSpeakers() |
| 111 | .values()) { | 112 | .values()) { |
| 112 | log.debug("Start to set up BGP paths for BGP speaker: {}", | 113 | log.debug("Start to set up BGP paths for BGP speaker: {}", |
| ... | @@ -117,9 +118,12 @@ public class PeerConnectivityManager { | ... | @@ -117,9 +118,12 @@ public class PeerConnectivityManager { |
| 117 | log.debug("Start to set up BGP paths between BGP speaker: {} " | 118 | log.debug("Start to set up BGP paths between BGP speaker: {} " |
| 118 | + "to BGP peer: {}", bgpSpeaker, bgpPeer); | 119 | + "to BGP peer: {}", bgpSpeaker, bgpPeer); |
| 119 | 120 | ||
| 120 | - buildPeerIntents(bgpSpeaker, bgpPeer); | 121 | + intents.addAll(buildPeerIntents(bgpSpeaker, bgpPeer)); |
| 121 | } | 122 | } |
| 122 | } | 123 | } |
| 124 | + | ||
| 125 | + // Submit all the intents. | ||
| 126 | + intentSynchronizer.submitPeerIntents(intents); | ||
| 123 | } | 127 | } |
| 124 | 128 | ||
| 125 | /** | 129 | /** |
| ... | @@ -128,9 +132,12 @@ public class PeerConnectivityManager { | ... | @@ -128,9 +132,12 @@ public class PeerConnectivityManager { |
| 128 | * | 132 | * |
| 129 | * @param bgpSpeaker the BGP speaker | 133 | * @param bgpSpeaker the BGP speaker |
| 130 | * @param bgpPeer the BGP peer | 134 | * @param bgpPeer the BGP peer |
| 135 | + * @return the intents to install | ||
| 131 | */ | 136 | */ |
| 132 | - private void buildPeerIntents(BgpSpeaker bgpSpeaker, BgpPeer bgpPeer) { | 137 | + private Collection<PointToPointIntent> buildPeerIntents( |
| 133 | - List<Intent> intents = new ArrayList<Intent>(); | 138 | + BgpSpeaker bgpSpeaker, |
| 139 | + BgpPeer bgpPeer) { | ||
| 140 | + List<PointToPointIntent> intents = new ArrayList<>(); | ||
| 134 | 141 | ||
| 135 | ConnectPoint bgpdConnectPoint = bgpSpeaker.connectPoint(); | 142 | ConnectPoint bgpdConnectPoint = bgpSpeaker.connectPoint(); |
| 136 | 143 | ||
| ... | @@ -142,7 +149,7 @@ public class PeerConnectivityManager { | ... | @@ -142,7 +149,7 @@ public class PeerConnectivityManager { |
| 142 | 149 | ||
| 143 | if (peerInterface == null) { | 150 | if (peerInterface == null) { |
| 144 | log.error("No interface found for peer {}", bgpPeer.ipAddress()); | 151 | log.error("No interface found for peer {}", bgpPeer.ipAddress()); |
| 145 | - return; | 152 | + return intents; |
| 146 | } | 153 | } |
| 147 | 154 | ||
| 148 | IpAddress bgpdAddress = null; | 155 | IpAddress bgpdAddress = null; |
| ... | @@ -156,7 +163,7 @@ public class PeerConnectivityManager { | ... | @@ -156,7 +163,7 @@ public class PeerConnectivityManager { |
| 156 | if (bgpdAddress == null) { | 163 | if (bgpdAddress == null) { |
| 157 | log.debug("No IP address found for peer {} on interface {}", | 164 | log.debug("No IP address found for peer {} on interface {}", |
| 158 | bgpPeer, bgpPeer.connectPoint()); | 165 | bgpPeer, bgpPeer.connectPoint()); |
| 159 | - return; | 166 | + return intents; |
| 160 | } | 167 | } |
| 161 | 168 | ||
| 162 | IpAddress bgpdPeerAddress = bgpPeer.ipAddress(); | 169 | IpAddress bgpdPeerAddress = bgpPeer.ipAddress(); |
| ... | @@ -231,11 +238,7 @@ public class PeerConnectivityManager { | ... | @@ -231,11 +238,7 @@ public class PeerConnectivityManager { |
| 231 | intents.add(new PointToPointIntent(appId, selector, treatment, | 238 | intents.add(new PointToPointIntent(appId, selector, treatment, |
| 232 | bgpdPeerConnectPoint, bgpdConnectPoint)); | 239 | bgpdPeerConnectPoint, bgpdConnectPoint)); |
| 233 | 240 | ||
| 234 | - // Submit all the intents. | 241 | + return intents; |
| 235 | - // TODO submit as a batch | ||
| 236 | - for (Intent intent : intents) { | ||
| 237 | - intentService.submit(intent); | ||
| 238 | - } | ||
| 239 | } | 242 | } |
| 240 | 243 | ||
| 241 | /** | 244 | /** |
| ... | @@ -249,7 +252,8 @@ public class PeerConnectivityManager { | ... | @@ -249,7 +252,8 @@ public class PeerConnectivityManager { |
| 249 | * @return the new traffic selector | 252 | * @return the new traffic selector |
| 250 | */ | 253 | */ |
| 251 | private TrafficSelector buildSelector(byte ipProto, IpAddress srcIp, | 254 | private TrafficSelector buildSelector(byte ipProto, IpAddress srcIp, |
| 252 | - IpAddress dstIp, Short srcTcpPort, Short dstTcpPort) { | 255 | + IpAddress dstIp, Short srcTcpPort, |
| 256 | + Short dstTcpPort) { | ||
| 253 | TrafficSelector.Builder builder = DefaultTrafficSelector.builder() | 257 | TrafficSelector.Builder builder = DefaultTrafficSelector.builder() |
| 254 | .matchEthType(Ethernet.TYPE_IPV4) | 258 | .matchEthType(Ethernet.TYPE_IPV4) |
| 255 | .matchIPProtocol(ipProto) | 259 | .matchIPProtocol(ipProto) | ... | ... |
| ... | @@ -92,18 +92,19 @@ public class Router implements RouteListener { | ... | @@ -92,18 +92,19 @@ public class Router implements RouteListener { |
| 92 | * | 92 | * |
| 93 | * @param appId the application ID | 93 | * @param appId the application ID |
| 94 | * @param intentSynchronizer the intent synchronizer | 94 | * @param intentSynchronizer the intent synchronizer |
| 95 | - * @param hostService the host service | ||
| 96 | * @param configService the configuration service | 95 | * @param configService the configuration service |
| 97 | * @param interfaceService the interface service | 96 | * @param interfaceService the interface service |
| 97 | + * @param hostService the host service | ||
| 98 | */ | 98 | */ |
| 99 | public Router(ApplicationId appId, IntentSynchronizer intentSynchronizer, | 99 | public Router(ApplicationId appId, IntentSynchronizer intentSynchronizer, |
| 100 | - HostService hostService, SdnIpConfigService configService, | 100 | + SdnIpConfigService configService, |
| 101 | - InterfaceService interfaceService) { | 101 | + InterfaceService interfaceService, |
| 102 | + HostService hostService) { | ||
| 102 | this.appId = appId; | 103 | this.appId = appId; |
| 103 | this.intentSynchronizer = intentSynchronizer; | 104 | this.intentSynchronizer = intentSynchronizer; |
| 104 | - this.hostService = hostService; | ||
| 105 | this.configService = configService; | 105 | this.configService = configService; |
| 106 | this.interfaceService = interfaceService; | 106 | this.interfaceService = interfaceService; |
| 107 | + this.hostService = hostService; | ||
| 107 | 108 | ||
| 108 | this.hostListener = new InternalHostListener(); | 109 | this.hostListener = new InternalHostListener(); |
| 109 | 110 | ... | ... |
| ... | @@ -18,8 +18,6 @@ package org.onlab.onos.sdnip; | ... | @@ -18,8 +18,6 @@ package org.onlab.onos.sdnip; |
| 18 | import static org.slf4j.LoggerFactory.getLogger; | 18 | import static org.slf4j.LoggerFactory.getLogger; |
| 19 | 19 | ||
| 20 | import java.util.Collection; | 20 | import java.util.Collection; |
| 21 | -import java.util.concurrent.ExecutorService; | ||
| 22 | -import java.util.concurrent.Executors; | ||
| 23 | 21 | ||
| 24 | import org.apache.felix.scr.annotations.Activate; | 22 | import org.apache.felix.scr.annotations.Activate; |
| 25 | import org.apache.felix.scr.annotations.Component; | 23 | import org.apache.felix.scr.annotations.Component; |
| ... | @@ -27,6 +25,11 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -27,6 +25,11 @@ import org.apache.felix.scr.annotations.Deactivate; |
| 27 | import org.apache.felix.scr.annotations.Reference; | 25 | import org.apache.felix.scr.annotations.Reference; |
| 28 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 26 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
| 29 | import org.apache.felix.scr.annotations.Service; | 27 | import org.apache.felix.scr.annotations.Service; |
| 28 | +import org.onlab.onos.cluster.ClusterService; | ||
| 29 | +import org.onlab.onos.cluster.ControllerNode; | ||
| 30 | +import org.onlab.onos.cluster.LeadershipEvent; | ||
| 31 | +import org.onlab.onos.cluster.LeadershipEventListener; | ||
| 32 | +import org.onlab.onos.cluster.LeadershipService; | ||
| 30 | import org.onlab.onos.core.ApplicationId; | 33 | import org.onlab.onos.core.ApplicationId; |
| 31 | import org.onlab.onos.core.CoreService; | 34 | import org.onlab.onos.core.CoreService; |
| 32 | import org.onlab.onos.net.host.HostService; | 35 | import org.onlab.onos.net.host.HostService; |
| ... | @@ -35,11 +38,8 @@ import org.onlab.onos.sdnip.bgp.BgpRouteEntry; | ... | @@ -35,11 +38,8 @@ import org.onlab.onos.sdnip.bgp.BgpRouteEntry; |
| 35 | import org.onlab.onos.sdnip.bgp.BgpSession; | 38 | import org.onlab.onos.sdnip.bgp.BgpSession; |
| 36 | import org.onlab.onos.sdnip.bgp.BgpSessionManager; | 39 | import org.onlab.onos.sdnip.bgp.BgpSessionManager; |
| 37 | import org.onlab.onos.sdnip.config.SdnIpConfigReader; | 40 | import org.onlab.onos.sdnip.config.SdnIpConfigReader; |
| 38 | -import org.onlab.onos.store.service.Lock; | ||
| 39 | -import org.onlab.onos.store.service.LockService; | ||
| 40 | -import org.slf4j.Logger; | ||
| 41 | 41 | ||
| 42 | -import com.google.common.util.concurrent.ThreadFactoryBuilder; | 42 | +import org.slf4j.Logger; |
| 43 | 43 | ||
| 44 | /** | 44 | /** |
| 45 | * Component for the SDN-IP peering application. | 45 | * Component for the SDN-IP peering application. |
| ... | @@ -65,55 +65,49 @@ public class SdnIp implements SdnIpService { | ... | @@ -65,55 +65,49 @@ public class SdnIp implements SdnIpService { |
| 65 | protected HostService hostService; | 65 | protected HostService hostService; |
| 66 | 66 | ||
| 67 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 67 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 68 | - protected LockService lockService; | 68 | + protected ClusterService clusterService; |
| 69 | + | ||
| 70 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 71 | + protected LeadershipService leadershipService; | ||
| 69 | 72 | ||
| 70 | private IntentSynchronizer intentSynchronizer; | 73 | private IntentSynchronizer intentSynchronizer; |
| 71 | private SdnIpConfigReader config; | 74 | private SdnIpConfigReader config; |
| 72 | private PeerConnectivityManager peerConnectivity; | 75 | private PeerConnectivityManager peerConnectivity; |
| 73 | private Router router; | 76 | private Router router; |
| 74 | private BgpSessionManager bgpSessionManager; | 77 | private BgpSessionManager bgpSessionManager; |
| 75 | - | 78 | + private LeadershipEventListener leadershipEventListener = |
| 76 | - private ExecutorService leaderElectionExecutor; | 79 | + new InnerLeadershipEventListener(); |
| 77 | - private Lock leaderLock; | 80 | + ApplicationId appId; |
| 78 | - private volatile boolean isShutdown = true; | 81 | + private ControllerNode localControllerNode; |
| 79 | 82 | ||
| 80 | @Activate | 83 | @Activate |
| 81 | protected void activate() { | 84 | protected void activate() { |
| 82 | log.info("SDN-IP started"); | 85 | log.info("SDN-IP started"); |
| 83 | - isShutdown = false; | ||
| 84 | 86 | ||
| 85 | - ApplicationId appId = coreService.registerApplication(SDN_IP_APP); | 87 | + appId = coreService.registerApplication(SDN_IP_APP); |
| 86 | config = new SdnIpConfigReader(); | 88 | config = new SdnIpConfigReader(); |
| 87 | config.init(); | 89 | config.init(); |
| 88 | 90 | ||
| 91 | + localControllerNode = clusterService.getLocalNode(); | ||
| 92 | + | ||
| 89 | InterfaceService interfaceService = | 93 | InterfaceService interfaceService = |
| 90 | new HostToInterfaceAdaptor(hostService); | 94 | new HostToInterfaceAdaptor(hostService); |
| 91 | 95 | ||
| 92 | intentSynchronizer = new IntentSynchronizer(appId, intentService); | 96 | intentSynchronizer = new IntentSynchronizer(appId, intentService); |
| 93 | intentSynchronizer.start(); | 97 | intentSynchronizer.start(); |
| 94 | 98 | ||
| 95 | - peerConnectivity = new PeerConnectivityManager(appId, config, | 99 | + peerConnectivity = new PeerConnectivityManager(appId, |
| 96 | - interfaceService, intentService); | 100 | + intentSynchronizer, |
| 101 | + config, | ||
| 102 | + interfaceService); | ||
| 97 | peerConnectivity.start(); | 103 | peerConnectivity.start(); |
| 98 | 104 | ||
| 99 | - router = new Router(appId, intentSynchronizer, hostService, config, | 105 | + router = new Router(appId, intentSynchronizer, config, |
| 100 | - interfaceService); | 106 | + interfaceService, hostService); |
| 101 | router.start(); | 107 | router.start(); |
| 102 | 108 | ||
| 103 | - leaderLock = lockService.create(SDN_IP_APP + "/sdnIpLeaderLock"); | 109 | + leadershipService.addListener(leadershipEventListener); |
| 104 | - leaderElectionExecutor = Executors.newSingleThreadExecutor( | 110 | + leadershipService.runForLeadership(appId.name()); |
| 105 | - new ThreadFactoryBuilder() | ||
| 106 | - .setNameFormat("sdnip-leader-election-%d").build()); | ||
| 107 | - leaderElectionExecutor.execute(new Runnable() { | ||
| 108 | - @Override | ||
| 109 | - public void run() { | ||
| 110 | - doLeaderElectionThread(); | ||
| 111 | - } | ||
| 112 | - }); | ||
| 113 | - | ||
| 114 | - // Manually set the instance as the leader to allow testing | ||
| 115 | - // TODO change this when we get a leader election | ||
| 116 | - // intentSynchronizer.leaderChanged(true); | ||
| 117 | 111 | ||
| 118 | bgpSessionManager = new BgpSessionManager(router); | 112 | bgpSessionManager = new BgpSessionManager(router); |
| 119 | // TODO: the local BGP listen port number should be configurable | 113 | // TODO: the local BGP listen port number should be configurable |
| ... | @@ -124,17 +118,16 @@ public class SdnIp implements SdnIpService { | ... | @@ -124,17 +118,16 @@ public class SdnIp implements SdnIpService { |
| 124 | 118 | ||
| 125 | @Deactivate | 119 | @Deactivate |
| 126 | protected void deactivate() { | 120 | protected void deactivate() { |
| 127 | - isShutdown = true; | ||
| 128 | 121 | ||
| 129 | bgpSessionManager.stop(); | 122 | bgpSessionManager.stop(); |
| 130 | router.stop(); | 123 | router.stop(); |
| 131 | peerConnectivity.stop(); | 124 | peerConnectivity.stop(); |
| 132 | intentSynchronizer.stop(); | 125 | intentSynchronizer.stop(); |
| 133 | 126 | ||
| 134 | - // Stop the thread(s) | 127 | + leadershipService.withdraw(appId.name()); |
| 135 | - leaderElectionExecutor.shutdownNow(); | 128 | + leadershipService.removeListener(leadershipEventListener); |
| 136 | 129 | ||
| 137 | - log.info("Stopped"); | 130 | + log.info("SDN-IP Stopped"); |
| 138 | } | 131 | } |
| 139 | 132 | ||
| 140 | @Override | 133 | @Override |
| ... | @@ -162,63 +155,38 @@ public class SdnIp implements SdnIpService { | ... | @@ -162,63 +155,38 @@ public class SdnIp implements SdnIpService { |
| 162 | } | 155 | } |
| 163 | 156 | ||
| 164 | /** | 157 | /** |
| 165 | - * Performs the leader election. | 158 | + * A listener for Leadership Events. |
| 166 | */ | 159 | */ |
| 167 | - private void doLeaderElectionThread() { | 160 | + private class InnerLeadershipEventListener |
| 161 | + implements LeadershipEventListener { | ||
| 168 | 162 | ||
| 169 | - // | 163 | + @Override |
| 170 | - // Try to acquire the lock and keep extending it until the instance | 164 | + public void event(LeadershipEvent event) { |
| 171 | - // is shutdown. | 165 | + log.debug("Leadership Event: time = {} type = {} event = {}", |
| 172 | - // | 166 | + event.time(), event.type(), event); |
| 173 | - while (!isShutdown) { | ||
| 174 | - log.debug("SDN-IP Leader Election begin"); | ||
| 175 | 167 | ||
| 176 | - // Block until it becomes the leader | 168 | + if (!event.subject().topic().equals(appId.name())) { |
| 177 | - try { | 169 | + return; // Not our topic: ignore |
| 178 | - leaderLock.lock(LEASE_DURATION_MS); | 170 | + } |
| 171 | + if (!event.subject().leader().id().equals( | ||
| 172 | + localControllerNode.id())) { | ||
| 173 | + return; // The event is not about this instance: ignore | ||
| 174 | + } | ||
| 179 | 175 | ||
| 180 | - // This instance is the leader | 176 | + switch (event.type()) { |
| 177 | + case LEADER_ELECTED: | ||
| 181 | log.info("SDN-IP Leader Elected"); | 178 | log.info("SDN-IP Leader Elected"); |
| 182 | intentSynchronizer.leaderChanged(true); | 179 | intentSynchronizer.leaderChanged(true); |
| 183 | - | 180 | + break; |
| 184 | - // Keep extending the expiration until shutdown | 181 | + case LEADER_BOOTED: |
| 185 | - int extensionFailedCountdown = LEASE_EXTEND_RETRY_MAX - 1; | 182 | + log.info("SDN-IP Leader Lost Election"); |
| 186 | - | 183 | + intentSynchronizer.leaderChanged(false); |
| 187 | - // | 184 | + break; |
| 188 | - // Keep periodically extending the lock expiration. | 185 | + case LEADER_REELECTED: |
| 189 | - // If there are multiple back-to-back failures to extend (with | 186 | + break; |
| 190 | - // extra sleep time between retrials), then release the lock. | 187 | + default: |
| 191 | - // | 188 | + break; |
| 192 | - while (!isShutdown) { | ||
| 193 | - Thread.sleep(LEASE_DURATION_MS / LEASE_EXTEND_RETRY_MAX); | ||
| 194 | - if (leaderLock.extendExpiration(LEASE_DURATION_MS)) { | ||
| 195 | - log.trace("SDN-IP Leader Extended"); | ||
| 196 | - extensionFailedCountdown = LEASE_EXTEND_RETRY_MAX; | ||
| 197 | - } else { | ||
| 198 | - log.debug("SDN-IP Leader Cannot Extend Election"); | ||
| 199 | - if (!leaderLock.isLocked()) { | ||
| 200 | - log.debug("SDN-IP Leader Lock Lost"); | ||
| 201 | - intentSynchronizer.leaderChanged(false); | ||
| 202 | - break; // Try again to get the lock | ||
| 203 | - } | ||
| 204 | - extensionFailedCountdown--; | ||
| 205 | - if (extensionFailedCountdown <= 0) { | ||
| 206 | - // Failed too many times to extend. | ||
| 207 | - // Release the lock. | ||
| 208 | - log.debug("SDN-IP Leader Lock Released"); | ||
| 209 | - intentSynchronizer.leaderChanged(false); | ||
| 210 | - leaderLock.unlock(); | ||
| 211 | - break; // Try again to get the lock | ||
| 212 | - } | ||
| 213 | - } | ||
| 214 | - } | ||
| 215 | - } catch (InterruptedException e) { | ||
| 216 | - // Thread interrupted. Time to shutdown | ||
| 217 | - log.debug("SDN-IP Leader Interrupted"); | ||
| 218 | } | 189 | } |
| 219 | } | 190 | } |
| 220 | - // If we reach here, the instance was shutdown | ||
| 221 | - intentSynchronizer.leaderChanged(false); | ||
| 222 | - leaderLock.unlock(); | ||
| 223 | } | 191 | } |
| 224 | } | 192 | } | ... | ... |
| ... | @@ -5,16 +5,23 @@ import static org.easymock.EasyMock.createMock; | ... | @@ -5,16 +5,23 @@ import static org.easymock.EasyMock.createMock; |
| 5 | import static org.easymock.EasyMock.expect; | 5 | import static org.easymock.EasyMock.expect; |
| 6 | import static org.easymock.EasyMock.expectLastCall; | 6 | import static org.easymock.EasyMock.expectLastCall; |
| 7 | import static org.easymock.EasyMock.replay; | 7 | import static org.easymock.EasyMock.replay; |
| 8 | +import static org.easymock.EasyMock.reportMatcher; | ||
| 8 | import static org.easymock.EasyMock.reset; | 9 | import static org.easymock.EasyMock.reset; |
| 9 | import static org.easymock.EasyMock.verify; | 10 | import static org.easymock.EasyMock.verify; |
| 11 | +import static org.hamcrest.Matchers.is; | ||
| 10 | import static org.junit.Assert.assertEquals; | 12 | import static org.junit.Assert.assertEquals; |
| 11 | import static org.junit.Assert.assertFalse; | 13 | import static org.junit.Assert.assertFalse; |
| 14 | +import static org.junit.Assert.assertThat; | ||
| 12 | import static org.junit.Assert.assertTrue; | 15 | import static org.junit.Assert.assertTrue; |
| 13 | 16 | ||
| 14 | import java.util.HashSet; | 17 | import java.util.HashSet; |
| 18 | +import java.util.LinkedList; | ||
| 19 | +import java.util.List; | ||
| 15 | import java.util.Set; | 20 | import java.util.Set; |
| 16 | import java.util.concurrent.ConcurrentHashMap; | 21 | import java.util.concurrent.ConcurrentHashMap; |
| 17 | 22 | ||
| 23 | +import org.apache.commons.collections4.CollectionUtils; | ||
| 24 | +import org.easymock.IArgumentMatcher; | ||
| 18 | import org.junit.Before; | 25 | import org.junit.Before; |
| 19 | import org.junit.Test; | 26 | import org.junit.Test; |
| 20 | import org.onlab.junit.TestUtils; | 27 | import org.onlab.junit.TestUtils; |
| ... | @@ -35,10 +42,14 @@ import org.onlab.onos.net.host.HostListener; | ... | @@ -35,10 +42,14 @@ import org.onlab.onos.net.host.HostListener; |
| 35 | import org.onlab.onos.net.host.HostService; | 42 | import org.onlab.onos.net.host.HostService; |
| 36 | import org.onlab.onos.net.host.InterfaceIpAddress; | 43 | import org.onlab.onos.net.host.InterfaceIpAddress; |
| 37 | import org.onlab.onos.net.intent.Intent; | 44 | import org.onlab.onos.net.intent.Intent; |
| 45 | +import org.onlab.onos.net.intent.IntentId; | ||
| 46 | +import org.onlab.onos.net.intent.IntentOperation; | ||
| 47 | +import org.onlab.onos.net.intent.IntentOperations; | ||
| 38 | import org.onlab.onos.net.intent.IntentService; | 48 | import org.onlab.onos.net.intent.IntentService; |
| 39 | import org.onlab.onos.net.intent.IntentState; | 49 | import org.onlab.onos.net.intent.IntentState; |
| 40 | import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; | 50 | import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; |
| 41 | import org.onlab.onos.net.provider.ProviderId; | 51 | import org.onlab.onos.net.provider.ProviderId; |
| 52 | +import org.onlab.onos.sdnip.IntentSynchronizer.IntentKey; | ||
| 42 | import org.onlab.onos.sdnip.config.Interface; | 53 | import org.onlab.onos.sdnip.config.Interface; |
| 43 | import org.onlab.packet.Ethernet; | 54 | import org.onlab.packet.Ethernet; |
| 44 | import org.onlab.packet.IpAddress; | 55 | import org.onlab.packet.IpAddress; |
| ... | @@ -97,8 +108,8 @@ public class IntentSyncTest { | ... | @@ -97,8 +108,8 @@ public class IntentSyncTest { |
| 97 | intentService = createMock(IntentService.class); | 108 | intentService = createMock(IntentService.class); |
| 98 | 109 | ||
| 99 | intentSynchronizer = new IntentSynchronizer(APPID, intentService); | 110 | intentSynchronizer = new IntentSynchronizer(APPID, intentService); |
| 100 | - router = new Router(APPID, intentSynchronizer, | 111 | + router = new Router(APPID, intentSynchronizer, null, interfaceService, |
| 101 | - hostService, null, interfaceService); | 112 | + hostService); |
| 102 | } | 113 | } |
| 103 | 114 | ||
| 104 | /** | 115 | /** |
| ... | @@ -263,17 +274,16 @@ public class IntentSyncTest { | ... | @@ -263,17 +274,16 @@ public class IntentSyncTest { |
| 263 | // Compose a intent, which is equal to intent5 but the id is different. | 274 | // Compose a intent, which is equal to intent5 but the id is different. |
| 264 | MultiPointToSinglePointIntent intent5New = | 275 | MultiPointToSinglePointIntent intent5New = |
| 265 | staticIntentBuilder(intent5, routeEntry5, "00:00:00:00:00:01"); | 276 | staticIntentBuilder(intent5, routeEntry5, "00:00:00:00:00:01"); |
| 266 | - assertTrue(TestUtils.callMethod(intentSynchronizer, | 277 | + assertThat(IntentSynchronizer.IntentKey.equalIntents( |
| 267 | - "compareMultiPointToSinglePointIntents", | 278 | + intent5, intent5New), |
| 268 | - new Class<?>[] {MultiPointToSinglePointIntent.class, | 279 | + is(true)); |
| 269 | - MultiPointToSinglePointIntent.class}, | ||
| 270 | - intent5, intent5New).equals(true)); | ||
| 271 | assertFalse(intent5.equals(intent5New)); | 280 | assertFalse(intent5.equals(intent5New)); |
| 272 | 281 | ||
| 273 | MultiPointToSinglePointIntent intent6 = intentBuilder( | 282 | MultiPointToSinglePointIntent intent6 = intentBuilder( |
| 274 | routeEntry6.prefix(), "00:00:00:00:00:01", SW1_ETH1); | 283 | routeEntry6.prefix(), "00:00:00:00:00:01", SW1_ETH1); |
| 275 | 284 | ||
| 276 | - // Set up the bgpRoutes and pushedRouteIntents fields in Router class | 285 | + // Set up the bgpRoutes field in Router class and routeIntents fields |
| 286 | + // in IntentSynchronizer class | ||
| 277 | InvertedRadixTree<RouteEntry> bgpRoutes = | 287 | InvertedRadixTree<RouteEntry> bgpRoutes = |
| 278 | new ConcurrentInvertedRadixTree<>( | 288 | new ConcurrentInvertedRadixTree<>( |
| 279 | new DefaultByteArrayNodeFactory()); | 289 | new DefaultByteArrayNodeFactory()); |
| ... | @@ -292,15 +302,14 @@ public class IntentSyncTest { | ... | @@ -292,15 +302,14 @@ public class IntentSyncTest { |
| 292 | TestUtils.setField(router, "bgpRoutes", bgpRoutes); | 302 | TestUtils.setField(router, "bgpRoutes", bgpRoutes); |
| 293 | 303 | ||
| 294 | ConcurrentHashMap<Ip4Prefix, MultiPointToSinglePointIntent> | 304 | ConcurrentHashMap<Ip4Prefix, MultiPointToSinglePointIntent> |
| 295 | - pushedRouteIntents = new ConcurrentHashMap<>(); | 305 | + routeIntents = new ConcurrentHashMap<>(); |
| 296 | - pushedRouteIntents.put(routeEntry1.prefix(), intent1); | 306 | + routeIntents.put(routeEntry1.prefix(), intent1); |
| 297 | - pushedRouteIntents.put(routeEntry3.prefix(), intent3); | 307 | + routeIntents.put(routeEntry3.prefix(), intent3); |
| 298 | - pushedRouteIntents.put(routeEntry4Update.prefix(), intent4Update); | 308 | + routeIntents.put(routeEntry4Update.prefix(), intent4Update); |
| 299 | - pushedRouteIntents.put(routeEntry5.prefix(), intent5New); | 309 | + routeIntents.put(routeEntry5.prefix(), intent5New); |
| 300 | - pushedRouteIntents.put(routeEntry6.prefix(), intent6); | 310 | + routeIntents.put(routeEntry6.prefix(), intent6); |
| 301 | - pushedRouteIntents.put(routeEntry7.prefix(), intent7); | 311 | + routeIntents.put(routeEntry7.prefix(), intent7); |
| 302 | - TestUtils.setField(intentSynchronizer, "pushedRouteIntents", | 312 | + TestUtils.setField(intentSynchronizer, "routeIntents", routeIntents); |
| 303 | - pushedRouteIntents); | ||
| 304 | 313 | ||
| 305 | // Set up expectation | 314 | // Set up expectation |
| 306 | reset(intentService); | 315 | reset(intentService); |
| ... | @@ -322,18 +331,26 @@ public class IntentSyncTest { | ... | @@ -322,18 +331,26 @@ public class IntentSyncTest { |
| 322 | .andReturn(IntentState.WITHDRAWING).anyTimes(); | 331 | .andReturn(IntentState.WITHDRAWING).anyTimes(); |
| 323 | expect(intentService.getIntents()).andReturn(intents).anyTimes(); | 332 | expect(intentService.getIntents()).andReturn(intents).anyTimes(); |
| 324 | 333 | ||
| 325 | - intentService.withdraw(intent2); | 334 | + IntentOperations.Builder builder = IntentOperations.builder(); |
| 326 | - intentService.submit(intent3); | 335 | + builder.addWithdrawOperation(intent2.id()); |
| 327 | - intentService.withdraw(intent4); | 336 | + builder.addWithdrawOperation(intent4.id()); |
| 328 | - intentService.submit(intent4Update); | 337 | + intentService.execute(eqExceptId(builder.build())); |
| 329 | - intentService.submit(intent6); | 338 | + |
| 330 | - intentService.submit(intent7); | 339 | + builder = IntentOperations.builder(); |
| 340 | + builder.addSubmitOperation(intent3); | ||
| 341 | + builder.addSubmitOperation(intent4Update); | ||
| 342 | + builder.addSubmitOperation(intent6); | ||
| 343 | + builder.addSubmitOperation(intent7); | ||
| 344 | + intentService.execute(eqExceptId(builder.build())); | ||
| 331 | replay(intentService); | 345 | replay(intentService); |
| 332 | 346 | ||
| 333 | // Start the test | 347 | // Start the test |
| 334 | intentSynchronizer.leaderChanged(true); | 348 | intentSynchronizer.leaderChanged(true); |
| 335 | - TestUtils.callMethod(intentSynchronizer, "syncIntents", | 349 | + /* |
| 350 | + TestUtils.callMethod(intentSynchronizer, "synchronizeIntents", | ||
| 336 | new Class<?>[] {}); | 351 | new Class<?>[] {}); |
| 352 | + */ | ||
| 353 | + intentSynchronizer.synchronizeIntents(); | ||
| 337 | 354 | ||
| 338 | // Verify | 355 | // Verify |
| 339 | assertEquals(router.getRoutes().size(), 6); | 356 | assertEquals(router.getRoutes().size(), 6); |
| ... | @@ -343,12 +360,12 @@ public class IntentSyncTest { | ... | @@ -343,12 +360,12 @@ public class IntentSyncTest { |
| 343 | assertTrue(router.getRoutes().contains(routeEntry5)); | 360 | assertTrue(router.getRoutes().contains(routeEntry5)); |
| 344 | assertTrue(router.getRoutes().contains(routeEntry6)); | 361 | assertTrue(router.getRoutes().contains(routeEntry6)); |
| 345 | 362 | ||
| 346 | - assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 6); | 363 | + assertEquals(intentSynchronizer.getRouteIntents().size(), 6); |
| 347 | - assertTrue(intentSynchronizer.getPushedRouteIntents().contains(intent1)); | 364 | + assertTrue(intentSynchronizer.getRouteIntents().contains(intent1)); |
| 348 | - assertTrue(intentSynchronizer.getPushedRouteIntents().contains(intent3)); | 365 | + assertTrue(intentSynchronizer.getRouteIntents().contains(intent3)); |
| 349 | - assertTrue(intentSynchronizer.getPushedRouteIntents().contains(intent4Update)); | 366 | + assertTrue(intentSynchronizer.getRouteIntents().contains(intent4Update)); |
| 350 | - assertTrue(intentSynchronizer.getPushedRouteIntents().contains(intent5)); | 367 | + assertTrue(intentSynchronizer.getRouteIntents().contains(intent5)); |
| 351 | - assertTrue(intentSynchronizer.getPushedRouteIntents().contains(intent6)); | 368 | + assertTrue(intentSynchronizer.getRouteIntents().contains(intent6)); |
| 352 | 369 | ||
| 353 | verify(intentService); | 370 | verify(intentService); |
| 354 | } | 371 | } |
| ... | @@ -410,4 +427,129 @@ public class IntentSyncTest { | ... | @@ -410,4 +427,129 @@ public class IntentSyncTest { |
| 410 | "ingressPoints", intent.ingressPoints()); | 427 | "ingressPoints", intent.ingressPoints()); |
| 411 | return intentNew; | 428 | return intentNew; |
| 412 | } | 429 | } |
| 430 | + | ||
| 431 | + /* | ||
| 432 | + * EasyMock matcher that matches {@link IntenOperations} but | ||
| 433 | + * ignores the {@link IntentId} when matching. | ||
| 434 | + * <p/> | ||
| 435 | + * The normal intent equals method tests that the intent IDs are equal, | ||
| 436 | + * however in these tests we can't know what the intent IDs will be in | ||
| 437 | + * advance, so we can't set up expected intents with the correct IDs. Thus, | ||
| 438 | + * the solution is to use an EasyMock matcher that verifies that all the | ||
| 439 | + * value properties of the provided intent match the expected values, but | ||
| 440 | + * ignores the intent ID when testing equality. | ||
| 441 | + */ | ||
| 442 | + private static final class IdAgnosticIntentOperationsMatcher implements | ||
| 443 | + IArgumentMatcher { | ||
| 444 | + | ||
| 445 | + private final IntentOperations intentOperations; | ||
| 446 | + private String providedString; | ||
| 447 | + | ||
| 448 | + /** | ||
| 449 | + * Constructor taking the expected intent operations to match against. | ||
| 450 | + * | ||
| 451 | + * @param intentOperations the expected intent operations | ||
| 452 | + */ | ||
| 453 | + public IdAgnosticIntentOperationsMatcher( | ||
| 454 | + IntentOperations intentOperations) { | ||
| 455 | + this.intentOperations = intentOperations; | ||
| 456 | + } | ||
| 457 | + | ||
| 458 | + @Override | ||
| 459 | + public void appendTo(StringBuffer strBuffer) { | ||
| 460 | + strBuffer.append("IntentOperationsMatcher unable to match: " | ||
| 461 | + + providedString); | ||
| 462 | + } | ||
| 463 | + | ||
| 464 | + @Override | ||
| 465 | + public boolean matches(Object object) { | ||
| 466 | + if (!(object instanceof IntentOperations)) { | ||
| 467 | + return false; | ||
| 468 | + } | ||
| 469 | + | ||
| 470 | + IntentOperations providedIntentOperations = | ||
| 471 | + (IntentOperations) object; | ||
| 472 | + providedString = providedIntentOperations.toString(); | ||
| 473 | + | ||
| 474 | + List<IntentKey> thisSubmitIntents = new LinkedList<>(); | ||
| 475 | + List<IntentId> thisWithdrawIntentIds = new LinkedList<>(); | ||
| 476 | + List<IntentKey> thisReplaceIntents = new LinkedList<>(); | ||
| 477 | + List<IntentKey> thisUpdateIntents = new LinkedList<>(); | ||
| 478 | + List<IntentKey> providedSubmitIntents = new LinkedList<>(); | ||
| 479 | + List<IntentId> providedWithdrawIntentIds = new LinkedList<>(); | ||
| 480 | + List<IntentKey> providedReplaceIntents = new LinkedList<>(); | ||
| 481 | + List<IntentKey> providedUpdateIntents = new LinkedList<>(); | ||
| 482 | + | ||
| 483 | + extractIntents(intentOperations, thisSubmitIntents, | ||
| 484 | + thisWithdrawIntentIds, thisReplaceIntents, | ||
| 485 | + thisUpdateIntents); | ||
| 486 | + extractIntents(providedIntentOperations, providedSubmitIntents, | ||
| 487 | + providedWithdrawIntentIds, providedReplaceIntents, | ||
| 488 | + providedUpdateIntents); | ||
| 489 | + | ||
| 490 | + return CollectionUtils.isEqualCollection(thisSubmitIntents, | ||
| 491 | + providedSubmitIntents) && | ||
| 492 | + CollectionUtils.isEqualCollection(thisWithdrawIntentIds, | ||
| 493 | + providedWithdrawIntentIds) && | ||
| 494 | + CollectionUtils.isEqualCollection(thisUpdateIntents, | ||
| 495 | + providedUpdateIntents) && | ||
| 496 | + CollectionUtils.isEqualCollection(thisReplaceIntents, | ||
| 497 | + providedReplaceIntents); | ||
| 498 | + } | ||
| 499 | + | ||
| 500 | + /** | ||
| 501 | + * Extracts the intents per operation type. Each intent is encapsulated | ||
| 502 | + * in IntentKey so it can be compared by excluding the Intent ID. | ||
| 503 | + * | ||
| 504 | + * @param intentOperations the container with the intent operations | ||
| 505 | + * to extract the intents from | ||
| 506 | + * @param submitIntents the SUBMIT intents | ||
| 507 | + * @param withdrawIntentIds the WITHDRAW intents IDs | ||
| 508 | + * @param replaceIntents the REPLACE intents | ||
| 509 | + * @param updateIntents the UPDATE intens | ||
| 510 | + */ | ||
| 511 | + private void extractIntents(IntentOperations intentOperations, | ||
| 512 | + List<IntentKey> submitIntents, | ||
| 513 | + List<IntentId> withdrawIntentIds, | ||
| 514 | + List<IntentKey> replaceIntents, | ||
| 515 | + List<IntentKey> updateIntents) { | ||
| 516 | + for (IntentOperation oper : intentOperations.operations()) { | ||
| 517 | + IntentId intentId; | ||
| 518 | + IntentKey intentKey; | ||
| 519 | + switch (oper.type()) { | ||
| 520 | + case SUBMIT: | ||
| 521 | + intentKey = new IntentKey(oper.intent()); | ||
| 522 | + submitIntents.add(intentKey); | ||
| 523 | + break; | ||
| 524 | + case WITHDRAW: | ||
| 525 | + intentId = oper.intentId(); | ||
| 526 | + withdrawIntentIds.add(intentId); | ||
| 527 | + break; | ||
| 528 | + case REPLACE: | ||
| 529 | + intentKey = new IntentKey(oper.intent()); | ||
| 530 | + replaceIntents.add(intentKey); | ||
| 531 | + break; | ||
| 532 | + case UPDATE: | ||
| 533 | + intentKey = new IntentKey(oper.intent()); | ||
| 534 | + updateIntents.add(intentKey); | ||
| 535 | + break; | ||
| 536 | + default: | ||
| 537 | + break; | ||
| 538 | + } | ||
| 539 | + } | ||
| 540 | + } | ||
| 541 | + } | ||
| 542 | + | ||
| 543 | + /** | ||
| 544 | + * Matcher method to set an expected intent to match against (ignoring the | ||
| 545 | + * the intent ID). | ||
| 546 | + * | ||
| 547 | + * @param intent the expected intent | ||
| 548 | + * @return something of type IntentOperations | ||
| 549 | + */ | ||
| 550 | + private static IntentOperations eqExceptId( | ||
| 551 | + IntentOperations intentOperations) { | ||
| 552 | + reportMatcher(new IdAgnosticIntentOperationsMatcher(intentOperations)); | ||
| 553 | + return intentOperations; | ||
| 554 | + } | ||
| 413 | } | 555 | } | ... | ... |
| ... | @@ -20,6 +20,8 @@ import org.easymock.IArgumentMatcher; | ... | @@ -20,6 +20,8 @@ import org.easymock.IArgumentMatcher; |
| 20 | import org.junit.Before; | 20 | import org.junit.Before; |
| 21 | import org.junit.Ignore; | 21 | import org.junit.Ignore; |
| 22 | import org.junit.Test; | 22 | import org.junit.Test; |
| 23 | +import org.onlab.junit.TestUtils; | ||
| 24 | +import org.onlab.junit.TestUtils.TestUtilsException; | ||
| 23 | import org.onlab.onos.core.ApplicationId; | 25 | import org.onlab.onos.core.ApplicationId; |
| 24 | import org.onlab.onos.net.ConnectPoint; | 26 | import org.onlab.onos.net.ConnectPoint; |
| 25 | import org.onlab.onos.net.DeviceId; | 27 | import org.onlab.onos.net.DeviceId; |
| ... | @@ -70,9 +72,10 @@ public class PeerConnectivityManagerTest { | ... | @@ -70,9 +72,10 @@ public class PeerConnectivityManagerTest { |
| 70 | }; | 72 | }; |
| 71 | 73 | ||
| 72 | private PeerConnectivityManager peerConnectivityManager; | 74 | private PeerConnectivityManager peerConnectivityManager; |
| 73 | - private IntentService intentService; | 75 | + private IntentSynchronizer intentSynchronizer; |
| 74 | private SdnIpConfigService configInfoService; | 76 | private SdnIpConfigService configInfoService; |
| 75 | private InterfaceService interfaceService; | 77 | private InterfaceService interfaceService; |
| 78 | + private IntentService intentService; | ||
| 76 | 79 | ||
| 77 | private Map<String, BgpSpeaker> bgpSpeakers; | 80 | private Map<String, BgpSpeaker> bgpSpeakers; |
| 78 | private Map<String, Interface> interfaces; | 81 | private Map<String, Interface> interfaces; |
| ... | @@ -525,8 +528,10 @@ public class PeerConnectivityManagerTest { | ... | @@ -525,8 +528,10 @@ public class PeerConnectivityManagerTest { |
| 525 | 528 | ||
| 526 | /** | 529 | /** |
| 527 | * Initializes peer connectivity testing environment. | 530 | * Initializes peer connectivity testing environment. |
| 531 | + * | ||
| 532 | + * @throws TestUtilsException if exceptions when using TestUtils | ||
| 528 | */ | 533 | */ |
| 529 | - private void initPeerConnectivity() { | 534 | + private void initPeerConnectivity() throws TestUtilsException { |
| 530 | 535 | ||
| 531 | configInfoService = createMock(SdnIpConfigService.class); | 536 | configInfoService = createMock(SdnIpConfigService.class); |
| 532 | expect(configInfoService.getBgpPeers()).andReturn(peers).anyTimes(); | 537 | expect(configInfoService.getBgpPeers()).andReturn(peers).anyTimes(); |
| ... | @@ -536,8 +541,13 @@ public class PeerConnectivityManagerTest { | ... | @@ -536,8 +541,13 @@ public class PeerConnectivityManagerTest { |
| 536 | intentService = createMock(IntentService.class); | 541 | intentService = createMock(IntentService.class); |
| 537 | replay(intentService); | 542 | replay(intentService); |
| 538 | 543 | ||
| 539 | - peerConnectivityManager = new PeerConnectivityManager(APPID, configInfoService, | 544 | + intentSynchronizer = new IntentSynchronizer(APPID, intentService); |
| 540 | - interfaceService, intentService); | 545 | + intentSynchronizer.leaderChanged(true); |
| 546 | + TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); | ||
| 547 | + | ||
| 548 | + peerConnectivityManager = | ||
| 549 | + new PeerConnectivityManager(APPID, intentSynchronizer, | ||
| 550 | + configInfoService, interfaceService); | ||
| 541 | } | 551 | } |
| 542 | 552 | ||
| 543 | /* | 553 | /* | ... | ... |
| ... | @@ -115,8 +115,8 @@ public class RouterTest { | ... | @@ -115,8 +115,8 @@ public class RouterTest { |
| 115 | intentService = createMock(IntentService.class); | 115 | intentService = createMock(IntentService.class); |
| 116 | 116 | ||
| 117 | intentSynchronizer = new IntentSynchronizer(APPID, intentService); | 117 | intentSynchronizer = new IntentSynchronizer(APPID, intentService); |
| 118 | - router = new Router(APPID, intentSynchronizer, | 118 | + router = new Router(APPID, intentSynchronizer, sdnIpConfigService, |
| 119 | - hostService, sdnIpConfigService, interfaceService); | 119 | + interfaceService, hostService); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | /** | 122 | /** |
| ... | @@ -267,8 +267,8 @@ public class RouterTest { | ... | @@ -267,8 +267,8 @@ public class RouterTest { |
| 267 | // Verify | 267 | // Verify |
| 268 | assertEquals(router.getRoutes().size(), 1); | 268 | assertEquals(router.getRoutes().size(), 1); |
| 269 | assertTrue(router.getRoutes().contains(routeEntry)); | 269 | assertTrue(router.getRoutes().contains(routeEntry)); |
| 270 | - assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 1); | 270 | + assertEquals(intentSynchronizer.getRouteIntents().size(), 1); |
| 271 | - assertEquals(intentSynchronizer.getPushedRouteIntents().iterator().next(), | 271 | + assertEquals(intentSynchronizer.getRouteIntents().iterator().next(), |
| 272 | intent); | 272 | intent); |
| 273 | verify(intentService); | 273 | verify(intentService); |
| 274 | } | 274 | } |
| ... | @@ -347,8 +347,8 @@ public class RouterTest { | ... | @@ -347,8 +347,8 @@ public class RouterTest { |
| 347 | // Verify | 347 | // Verify |
| 348 | assertEquals(router.getRoutes().size(), 1); | 348 | assertEquals(router.getRoutes().size(), 1); |
| 349 | assertTrue(router.getRoutes().contains(routeEntryUpdate)); | 349 | assertTrue(router.getRoutes().contains(routeEntryUpdate)); |
| 350 | - assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 1); | 350 | + assertEquals(intentSynchronizer.getRouteIntents().size(), 1); |
| 351 | - assertEquals(intentSynchronizer.getPushedRouteIntents().iterator().next(), | 351 | + assertEquals(intentSynchronizer.getRouteIntents().iterator().next(), |
| 352 | intentNew); | 352 | intentNew); |
| 353 | verify(intentService); | 353 | verify(intentService); |
| 354 | } | 354 | } |
| ... | @@ -397,7 +397,7 @@ public class RouterTest { | ... | @@ -397,7 +397,7 @@ public class RouterTest { |
| 397 | 397 | ||
| 398 | // Verify | 398 | // Verify |
| 399 | assertEquals(router.getRoutes().size(), 0); | 399 | assertEquals(router.getRoutes().size(), 0); |
| 400 | - assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 0); | 400 | + assertEquals(intentSynchronizer.getRouteIntents().size(), 0); |
| 401 | verify(intentService); | 401 | verify(intentService); |
| 402 | } | 402 | } |
| 403 | 403 | ||
| ... | @@ -425,7 +425,7 @@ public class RouterTest { | ... | @@ -425,7 +425,7 @@ public class RouterTest { |
| 425 | // Verify | 425 | // Verify |
| 426 | assertEquals(router.getRoutes().size(), 1); | 426 | assertEquals(router.getRoutes().size(), 1); |
| 427 | assertTrue(router.getRoutes().contains(routeEntry)); | 427 | assertTrue(router.getRoutes().contains(routeEntry)); |
| 428 | - assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 0); | 428 | + assertEquals(intentSynchronizer.getRouteIntents().size(), 0); |
| 429 | verify(intentService); | 429 | verify(intentService); |
| 430 | } | 430 | } |
| 431 | } | 431 | } | ... | ... |
| ... | @@ -117,7 +117,7 @@ public class RouterTestWithAsyncArp { | ... | @@ -117,7 +117,7 @@ public class RouterTestWithAsyncArp { |
| 117 | 117 | ||
| 118 | intentSynchronizer = new IntentSynchronizer(APPID, intentService); | 118 | intentSynchronizer = new IntentSynchronizer(APPID, intentService); |
| 119 | router = new Router(APPID, intentSynchronizer, | 119 | router = new Router(APPID, intentSynchronizer, |
| 120 | - hostService, sdnIpConfigService, interfaceService); | 120 | + sdnIpConfigService, interfaceService, hostService); |
| 121 | internalHostListener = router.new InternalHostListener(); | 121 | internalHostListener = router.new InternalHostListener(); |
| 122 | } | 122 | } |
| 123 | 123 | ||
| ... | @@ -229,8 +229,8 @@ public class RouterTestWithAsyncArp { | ... | @@ -229,8 +229,8 @@ public class RouterTestWithAsyncArp { |
| 229 | // Verify | 229 | // Verify |
| 230 | assertEquals(router.getRoutes().size(), 1); | 230 | assertEquals(router.getRoutes().size(), 1); |
| 231 | assertTrue(router.getRoutes().contains(routeEntry)); | 231 | assertTrue(router.getRoutes().contains(routeEntry)); |
| 232 | - assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 1); | 232 | + assertEquals(intentSynchronizer.getRouteIntents().size(), 1); |
| 233 | - assertEquals(intentSynchronizer.getPushedRouteIntents().iterator().next(), | 233 | + assertEquals(intentSynchronizer.getRouteIntents().iterator().next(), |
| 234 | intent); | 234 | intent); |
| 235 | verify(intentService); | 235 | verify(intentService); |
| 236 | verify(hostService); | 236 | verify(hostService); |
| ... | @@ -254,9 +254,9 @@ public class RouterTestWithAsyncArp { | ... | @@ -254,9 +254,9 @@ public class RouterTestWithAsyncArp { |
| 254 | MultiPointToSinglePointIntent intent = staticIntentBuilder(); | 254 | MultiPointToSinglePointIntent intent = staticIntentBuilder(); |
| 255 | 255 | ||
| 256 | // Set up the bgpRoutes field of Router class with existing route, and | 256 | // Set up the bgpRoutes field of Router class with existing route, and |
| 257 | - // pushedRouteIntents field with the corresponding existing intent | 257 | + // routeIntents field with the corresponding existing intent |
| 258 | setBgpRoutesField(routeEntry); | 258 | setBgpRoutesField(routeEntry); |
| 259 | - setPushedRouteIntentsField(routeEntry, intent); | 259 | + setRouteIntentsField(routeEntry, intent); |
| 260 | 260 | ||
| 261 | // Start to construct a new route entry and new intent | 261 | // Start to construct a new route entry and new intent |
| 262 | RouteEntry routeEntryUpdate = new RouteEntry( | 262 | RouteEntry routeEntryUpdate = new RouteEntry( |
| ... | @@ -312,8 +312,8 @@ public class RouterTestWithAsyncArp { | ... | @@ -312,8 +312,8 @@ public class RouterTestWithAsyncArp { |
| 312 | // Verify | 312 | // Verify |
| 313 | assertEquals(router.getRoutes().size(), 1); | 313 | assertEquals(router.getRoutes().size(), 1); |
| 314 | assertTrue(router.getRoutes().contains(routeEntryUpdate)); | 314 | assertTrue(router.getRoutes().contains(routeEntryUpdate)); |
| 315 | - assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 1); | 315 | + assertEquals(intentSynchronizer.getRouteIntents().size(), 1); |
| 316 | - assertEquals(intentSynchronizer.getPushedRouteIntents().iterator().next(), | 316 | + assertEquals(intentSynchronizer.getRouteIntents().iterator().next(), |
| 317 | intentNew); | 317 | intentNew); |
| 318 | verify(intentService); | 318 | verify(intentService); |
| 319 | verify(hostService); | 319 | verify(hostService); |
| ... | @@ -334,9 +334,9 @@ public class RouterTestWithAsyncArp { | ... | @@ -334,9 +334,9 @@ public class RouterTestWithAsyncArp { |
| 334 | MultiPointToSinglePointIntent intent = staticIntentBuilder(); | 334 | MultiPointToSinglePointIntent intent = staticIntentBuilder(); |
| 335 | 335 | ||
| 336 | // Set up the bgpRoutes field of Router class with existing route, and | 336 | // Set up the bgpRoutes field of Router class with existing route, and |
| 337 | - // pushedRouteIntents field with the corresponding existing intent | 337 | + // routeIntents field with the corresponding existing intent |
| 338 | setBgpRoutesField(routeEntry); | 338 | setBgpRoutesField(routeEntry); |
| 339 | - setPushedRouteIntentsField(routeEntry, intent); | 339 | + setRouteIntentsField(routeEntry, intent); |
| 340 | 340 | ||
| 341 | // Set up expectation | 341 | // Set up expectation |
| 342 | reset(intentService); | 342 | reset(intentService); |
| ... | @@ -350,7 +350,7 @@ public class RouterTestWithAsyncArp { | ... | @@ -350,7 +350,7 @@ public class RouterTestWithAsyncArp { |
| 350 | 350 | ||
| 351 | // Verify | 351 | // Verify |
| 352 | assertEquals(router.getRoutes().size(), 0); | 352 | assertEquals(router.getRoutes().size(), 0); |
| 353 | - assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 0); | 353 | + assertEquals(intentSynchronizer.getRouteIntents().size(), 0); |
| 354 | verify(intentService); | 354 | verify(intentService); |
| 355 | } | 355 | } |
| 356 | 356 | ||
| ... | @@ -397,17 +397,17 @@ public class RouterTestWithAsyncArp { | ... | @@ -397,17 +397,17 @@ public class RouterTestWithAsyncArp { |
| 397 | } | 397 | } |
| 398 | 398 | ||
| 399 | /** | 399 | /** |
| 400 | - * Sets pushedRouteIntentsField in Router class. | 400 | + * Sets routeIntentsField in IntentSynchronizer class. |
| 401 | * | 401 | * |
| 402 | * @throws TestUtilsException | 402 | * @throws TestUtilsException |
| 403 | */ | 403 | */ |
| 404 | - private void setPushedRouteIntentsField(RouteEntry routeEntry, | 404 | + private void setRouteIntentsField(RouteEntry routeEntry, |
| 405 | MultiPointToSinglePointIntent intent) | 405 | MultiPointToSinglePointIntent intent) |
| 406 | throws TestUtilsException { | 406 | throws TestUtilsException { |
| 407 | 407 | ||
| 408 | ConcurrentHashMap<Ip4Prefix, MultiPointToSinglePointIntent> | 408 | ConcurrentHashMap<Ip4Prefix, MultiPointToSinglePointIntent> |
| 409 | - pushedRouteIntents = new ConcurrentHashMap<>(); | 409 | + routeIntents = new ConcurrentHashMap<>(); |
| 410 | - pushedRouteIntents.put(routeEntry.prefix(), intent); | 410 | + routeIntents.put(routeEntry.prefix(), intent); |
| 411 | - TestUtils.setField(router, "pushedRouteIntents", pushedRouteIntents); | 411 | + TestUtils.setField(intentSynchronizer, "routeIntents", routeIntents); |
| 412 | } | 412 | } |
| 413 | } | 413 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -113,8 +113,8 @@ public class SdnIpTest { | ... | @@ -113,8 +113,8 @@ public class SdnIpTest { |
| 113 | random = new Random(); | 113 | random = new Random(); |
| 114 | 114 | ||
| 115 | intentSynchronizer = new IntentSynchronizer(APPID, intentService); | 115 | intentSynchronizer = new IntentSynchronizer(APPID, intentService); |
| 116 | - router = new Router(APPID, intentSynchronizer, hostService, | 116 | + router = new Router(APPID, intentSynchronizer, sdnIpConfigService, |
| 117 | - sdnIpConfigService, interfaceService); | 117 | + interfaceService, hostService); |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | /** | 120 | /** |
| ... | @@ -241,7 +241,7 @@ public class SdnIpTest { | ... | @@ -241,7 +241,7 @@ public class SdnIpTest { |
| 241 | latch.await(5000, TimeUnit.MILLISECONDS); | 241 | latch.await(5000, TimeUnit.MILLISECONDS); |
| 242 | 242 | ||
| 243 | assertEquals(router.getRoutes().size(), numRoutes); | 243 | assertEquals(router.getRoutes().size(), numRoutes); |
| 244 | - assertEquals(intentSynchronizer.getPushedRouteIntents().size(), | 244 | + assertEquals(intentSynchronizer.getRouteIntents().size(), |
| 245 | numRoutes); | 245 | numRoutes); |
| 246 | 246 | ||
| 247 | verify(intentService); | 247 | verify(intentService); |
| ... | @@ -317,7 +317,7 @@ public class SdnIpTest { | ... | @@ -317,7 +317,7 @@ public class SdnIpTest { |
| 317 | deleteCount.await(5000, TimeUnit.MILLISECONDS); | 317 | deleteCount.await(5000, TimeUnit.MILLISECONDS); |
| 318 | 318 | ||
| 319 | assertEquals(0, router.getRoutes().size()); | 319 | assertEquals(0, router.getRoutes().size()); |
| 320 | - assertEquals(0, intentSynchronizer.getPushedRouteIntents().size()); | 320 | + assertEquals(0, intentSynchronizer.getRouteIntents().size()); |
| 321 | verify(intentService); | 321 | verify(intentService); |
| 322 | } | 322 | } |
| 323 | 323 | ... | ... |
| ... | @@ -139,6 +139,12 @@ | ... | @@ -139,6 +139,12 @@ |
| 139 | </dependency> | 139 | </dependency> |
| 140 | 140 | ||
| 141 | <dependency> | 141 | <dependency> |
| 142 | + <groupId>org.apache.commons</groupId> | ||
| 143 | + <artifactId>commons-collections4</artifactId> | ||
| 144 | + <version>4.0</version> | ||
| 145 | + </dependency> | ||
| 146 | + | ||
| 147 | + <dependency> | ||
| 142 | <groupId>org.codehaus.jackson</groupId> | 148 | <groupId>org.codehaus.jackson</groupId> |
| 143 | <artifactId>jackson-core-asl</artifactId> | 149 | <artifactId>jackson-core-asl</artifactId> |
| 144 | <version>1.9.13</version> | 150 | <version>1.9.13</version> | ... | ... |
-
Please register or login to post a comment