Moved the BGP Route Intent synchronization mechanism from the Router class
to the new class IntentSynchronizer. Also, minor cleanup in some of the method names and access scope. Change-Id: I38257cd1d9516ef3b3dd50f23c28015054c73d70
Showing
10 changed files
with
524 additions
and
419 deletions
| 1 | +/* | ||
| 2 | + * Copyright 2014 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onlab.onos.sdnip; | ||
| 17 | + | ||
| 18 | +import java.util.Collection; | ||
| 19 | +import java.util.HashMap; | ||
| 20 | +import java.util.LinkedList; | ||
| 21 | +import java.util.List; | ||
| 22 | +import java.util.Map; | ||
| 23 | +import java.util.concurrent.ConcurrentHashMap; | ||
| 24 | +import java.util.concurrent.ExecutorService; | ||
| 25 | +import java.util.concurrent.Executors; | ||
| 26 | +import java.util.concurrent.Semaphore; | ||
| 27 | + | ||
| 28 | +import org.apache.commons.lang3.tuple.Pair; | ||
| 29 | +import org.onlab.onos.core.ApplicationId; | ||
| 30 | +import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion; | ||
| 31 | +import org.onlab.onos.net.flow.criteria.Criterion; | ||
| 32 | +import org.onlab.onos.net.intent.Intent; | ||
| 33 | +import org.onlab.onos.net.intent.IntentService; | ||
| 34 | +import org.onlab.onos.net.intent.IntentState; | ||
| 35 | +import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; | ||
| 36 | +import org.onlab.packet.Ip4Prefix; | ||
| 37 | +import org.slf4j.Logger; | ||
| 38 | +import org.slf4j.LoggerFactory; | ||
| 39 | + | ||
| 40 | +import com.google.common.base.Objects; | ||
| 41 | +import com.google.common.util.concurrent.ThreadFactoryBuilder; | ||
| 42 | + | ||
| 43 | +public class IntentSynchronizer { | ||
| 44 | + private static final Logger log = | ||
| 45 | + LoggerFactory.getLogger(IntentSynchronizer.class); | ||
| 46 | + | ||
| 47 | + private final ApplicationId appId; | ||
| 48 | + private final IntentService intentService; | ||
| 49 | + private final Map<Ip4Prefix, MultiPointToSinglePointIntent> pushedRouteIntents; | ||
| 50 | + | ||
| 51 | + // | ||
| 52 | + // State to deal with SDN-IP Leader election and pushing Intents | ||
| 53 | + // | ||
| 54 | + private final ExecutorService bgpIntentsSynchronizerExecutor; | ||
| 55 | + private final Semaphore intentsSynchronizerSemaphore = new Semaphore(0); | ||
| 56 | + private volatile boolean isElectedLeader = false; | ||
| 57 | + private volatile boolean isActivatedLeader = false; | ||
| 58 | + | ||
| 59 | + /** | ||
| 60 | + * Class constructor. | ||
| 61 | + * | ||
| 62 | + * @param appId the Application ID | ||
| 63 | + * @param intentService the intent service | ||
| 64 | + */ | ||
| 65 | + IntentSynchronizer(ApplicationId appId, IntentService intentService) { | ||
| 66 | + this.appId = appId; | ||
| 67 | + this.intentService = intentService; | ||
| 68 | + pushedRouteIntents = new ConcurrentHashMap<>(); | ||
| 69 | + | ||
| 70 | + bgpIntentsSynchronizerExecutor = Executors.newSingleThreadExecutor( | ||
| 71 | + new ThreadFactoryBuilder() | ||
| 72 | + .setNameFormat("bgp-intents-synchronizer-%d").build()); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + /** | ||
| 76 | + * Starts the synchronizer. | ||
| 77 | + */ | ||
| 78 | + public void start() { | ||
| 79 | + bgpIntentsSynchronizerExecutor.execute(new Runnable() { | ||
| 80 | + @Override | ||
| 81 | + public void run() { | ||
| 82 | + doIntentSynchronizationThread(); | ||
| 83 | + } | ||
| 84 | + }); | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + /** | ||
| 88 | + * Stops the synchronizer. | ||
| 89 | + */ | ||
| 90 | + public void stop() { | ||
| 91 | + // Stop the thread(s) | ||
| 92 | + bgpIntentsSynchronizerExecutor.shutdownNow(); | ||
| 93 | + | ||
| 94 | + // | ||
| 95 | + // Withdraw all SDN-IP intents | ||
| 96 | + // | ||
| 97 | + if (!isElectedLeader) { | ||
| 98 | + 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 | + } | ||
| 106 | + intentService.withdraw(intent); | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + pushedRouteIntents.clear(); | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + //@Override TODO hook this up to something | ||
| 113 | + public void leaderChanged(boolean isLeader) { | ||
| 114 | + log.debug("Leader changed: {}", isLeader); | ||
| 115 | + | ||
| 116 | + if (!isLeader) { | ||
| 117 | + this.isElectedLeader = false; | ||
| 118 | + this.isActivatedLeader = false; | ||
| 119 | + return; // Nothing to do | ||
| 120 | + } | ||
| 121 | + this.isActivatedLeader = false; | ||
| 122 | + this.isElectedLeader = true; | ||
| 123 | + | ||
| 124 | + // | ||
| 125 | + // Tell the Intents Synchronizer thread to start the synchronization | ||
| 126 | + // | ||
| 127 | + intentsSynchronizerSemaphore.release(); | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + /** | ||
| 131 | + * Gets the pushed route intents. | ||
| 132 | + * | ||
| 133 | + * @return the pushed route intents | ||
| 134 | + */ | ||
| 135 | + public Collection<MultiPointToSinglePointIntent> getPushedRouteIntents() { | ||
| 136 | + List<MultiPointToSinglePointIntent> pushedIntents = new LinkedList<>(); | ||
| 137 | + | ||
| 138 | + for (Map.Entry<Ip4Prefix, MultiPointToSinglePointIntent> entry : | ||
| 139 | + pushedRouteIntents.entrySet()) { | ||
| 140 | + pushedIntents.add(entry.getValue()); | ||
| 141 | + } | ||
| 142 | + return pushedIntents; | ||
| 143 | + } | ||
| 144 | + | ||
| 145 | + /** | ||
| 146 | + * Thread for Intent Synchronization. | ||
| 147 | + */ | ||
| 148 | + private void doIntentSynchronizationThread() { | ||
| 149 | + boolean interrupted = false; | ||
| 150 | + try { | ||
| 151 | + while (!interrupted) { | ||
| 152 | + try { | ||
| 153 | + intentsSynchronizerSemaphore.acquire(); | ||
| 154 | + // | ||
| 155 | + // Drain all permits, because a single synchronization is | ||
| 156 | + // sufficient. | ||
| 157 | + // | ||
| 158 | + intentsSynchronizerSemaphore.drainPermits(); | ||
| 159 | + } catch (InterruptedException e) { | ||
| 160 | + log.debug("Interrupted while waiting to become " + | ||
| 161 | + "Intent Synchronization leader"); | ||
| 162 | + interrupted = true; | ||
| 163 | + break; | ||
| 164 | + } | ||
| 165 | + syncIntents(); | ||
| 166 | + } | ||
| 167 | + } finally { | ||
| 168 | + if (interrupted) { | ||
| 169 | + Thread.currentThread().interrupt(); | ||
| 170 | + } | ||
| 171 | + } | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + /** | ||
| 175 | + * Submits a multi-point-to-single-point intent. | ||
| 176 | + * | ||
| 177 | + * @param prefix the IPv4 matching prefix for the intent to submit | ||
| 178 | + * @param intent the intent to submit | ||
| 179 | + */ | ||
| 180 | + void submitRouteIntent(Ip4Prefix prefix, | ||
| 181 | + MultiPointToSinglePointIntent intent) { | ||
| 182 | + synchronized (this) { | ||
| 183 | + if (isElectedLeader && isActivatedLeader) { | ||
| 184 | + log.debug("Intent installation: adding Intent for prefix: {}", | ||
| 185 | + prefix); | ||
| 186 | + intentService.submit(intent); | ||
| 187 | + } | ||
| 188 | + | ||
| 189 | + // Maintain the Intent | ||
| 190 | + pushedRouteIntents.put(prefix, intent); | ||
| 191 | + } | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + /** | ||
| 195 | + * Withdraws a multi-point-to-single-point intent. | ||
| 196 | + * | ||
| 197 | + * @param prefix the IPv4 matching prefix for the intent to withdraw. | ||
| 198 | + */ | ||
| 199 | + void withdrawRouteIntent(Ip4Prefix prefix) { | ||
| 200 | + synchronized (this) { | ||
| 201 | + MultiPointToSinglePointIntent intent = | ||
| 202 | + pushedRouteIntents.remove(prefix); | ||
| 203 | + | ||
| 204 | + if (intent == null) { | ||
| 205 | + log.debug("There is no intent in pushedRouteIntents to delete " + | ||
| 206 | + "for prefix: {}", prefix); | ||
| 207 | + return; | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | + if (isElectedLeader && isActivatedLeader) { | ||
| 211 | + log.debug("Intent installation: deleting Intent for prefix: {}", | ||
| 212 | + prefix); | ||
| 213 | + intentService.withdraw(intent); | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + /** | ||
| 219 | + * Performs Intents Synchronization between the internally stored Route | ||
| 220 | + * Intents and the installed Route Intents. | ||
| 221 | + */ | ||
| 222 | + private void syncIntents() { | ||
| 223 | + synchronized (this) { | ||
| 224 | + if (!isElectedLeader) { | ||
| 225 | + return; // Nothing to do: not the leader anymore | ||
| 226 | + } | ||
| 227 | + log.debug("Syncing SDN-IP Route Intents..."); | ||
| 228 | + | ||
| 229 | + Map<Ip4Prefix, MultiPointToSinglePointIntent> fetchedIntents = | ||
| 230 | + new HashMap<>(); | ||
| 231 | + | ||
| 232 | + // | ||
| 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()) { | ||
| 237 | + | ||
| 238 | + if (!(intent instanceof MultiPointToSinglePointIntent) | ||
| 239 | + || !intent.appId().equals(appId)) { | ||
| 240 | + continue; | ||
| 241 | + } | ||
| 242 | + MultiPointToSinglePointIntent mp2pIntent = | ||
| 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 | + } | ||
| 261 | + | ||
| 262 | + // | ||
| 263 | + // Compare for each prefix the local IN-MEMORY Intents with the | ||
| 264 | + // FETCHED Intents: | ||
| 265 | + // - If the IN-MEMORY Intent is same as the FETCHED Intent, store | ||
| 266 | + // the FETCHED Intent in the local memory (i.e., override the | ||
| 267 | + // IN-MEMORY Intent) to preserve the original Intent ID | ||
| 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 | + // | ||
| 278 | + Collection<Pair<Ip4Prefix, MultiPointToSinglePointIntent>> | ||
| 279 | + storeInMemoryIntents = new LinkedList<>(); | ||
| 280 | + Collection<Pair<Ip4Prefix, MultiPointToSinglePointIntent>> | ||
| 281 | + addIntents = new LinkedList<>(); | ||
| 282 | + Collection<Pair<Ip4Prefix, MultiPointToSinglePointIntent>> | ||
| 283 | + deleteIntents = new LinkedList<>(); | ||
| 284 | + for (Map.Entry<Ip4Prefix, MultiPointToSinglePointIntent> entry : | ||
| 285 | + pushedRouteIntents.entrySet()) { | ||
| 286 | + Ip4Prefix prefix = entry.getKey(); | ||
| 287 | + MultiPointToSinglePointIntent inMemoryIntent = | ||
| 288 | + entry.getValue(); | ||
| 289 | + MultiPointToSinglePointIntent fetchedIntent = | ||
| 290 | + fetchedIntents.get(prefix); | ||
| 291 | + | ||
| 292 | + if (fetchedIntent == null) { | ||
| 293 | + // | ||
| 294 | + // No FETCHED Intent for same prefix: push the IN-MEMORY | ||
| 295 | + // Intent. | ||
| 296 | + // | ||
| 297 | + addIntents.add(Pair.of(prefix, inMemoryIntent)); | ||
| 298 | + continue; | ||
| 299 | + } | ||
| 300 | + | ||
| 301 | + IntentState state = intentService.getIntentState(fetchedIntent.id()); | ||
| 302 | + if (state == IntentState.WITHDRAWING || | ||
| 303 | + state == IntentState.WITHDRAWN) { | ||
| 304 | + // The intent has been withdrawn but according to our route | ||
| 305 | + // table it should be installed. We'll reinstall it. | ||
| 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 | + } | ||
| 325 | + fetchedIntents.remove(prefix); | ||
| 326 | + } | ||
| 327 | + | ||
| 328 | + // | ||
| 329 | + // Any remaining FETCHED Intents have to be deleted/withdrawn | ||
| 330 | + // | ||
| 331 | + for (Map.Entry<Ip4Prefix, MultiPointToSinglePointIntent> entry : | ||
| 332 | + fetchedIntents.entrySet()) { | ||
| 333 | + Ip4Prefix prefix = entry.getKey(); | ||
| 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 | + } | ||
| 353 | + // | ||
| 354 | + isActivatedLeader = true; // Allow push of Intents | ||
| 355 | + for (Pair<Ip4Prefix, MultiPointToSinglePointIntent> pair : | ||
| 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 | + } | ||
| 367 | + // | ||
| 368 | + for (Pair<Ip4Prefix, MultiPointToSinglePointIntent> pair : | ||
| 369 | + addIntents) { | ||
| 370 | + Ip4Prefix prefix = pair.getLeft(); | ||
| 371 | + MultiPointToSinglePointIntent intent = pair.getRight(); | ||
| 372 | + if (!isElectedLeader) { | ||
| 373 | + isActivatedLeader = false; | ||
| 374 | + return; | ||
| 375 | + } | ||
| 376 | + log.debug("Intent synchronization: adding Intent for " + | ||
| 377 | + "prefix: {}", prefix); | ||
| 378 | + intentService.submit(intent); | ||
| 379 | + } | ||
| 380 | + if (!isElectedLeader) { | ||
| 381 | + isActivatedLeader = false; | ||
| 382 | + } | ||
| 383 | + log.debug("Syncing SDN-IP routes completed."); | ||
| 384 | + } | ||
| 385 | + } | ||
| 386 | + | ||
| 387 | + /** | ||
| 388 | + * Compares two Multi-point to Single Point Intents whether they represent | ||
| 389 | + * same logical intention. | ||
| 390 | + * | ||
| 391 | + * @param intent1 the first Intent to compare | ||
| 392 | + * @param intent2 the second Intent to compare | ||
| 393 | + * @return true if both Intents represent same logical intention, otherwise | ||
| 394 | + * false | ||
| 395 | + */ | ||
| 396 | + private boolean compareMultiPointToSinglePointIntents( | ||
| 397 | + MultiPointToSinglePointIntent intent1, | ||
| 398 | + MultiPointToSinglePointIntent intent2) { | ||
| 399 | + | ||
| 400 | + return Objects.equal(intent1.appId(), intent2.appId()) && | ||
| 401 | + Objects.equal(intent1.selector(), intent2.selector()) && | ||
| 402 | + Objects.equal(intent1.treatment(), intent2.treatment()) && | ||
| 403 | + Objects.equal(intent1.ingressPoints(), intent2.ingressPoints()) && | ||
| 404 | + Objects.equal(intent1.egressPoint(), intent2.egressPoint()); | ||
| 405 | + } | ||
| 406 | +} |
| ... | @@ -96,6 +96,13 @@ public class PeerConnectivityManager { | ... | @@ -96,6 +96,13 @@ public class PeerConnectivityManager { |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | /** | 98 | /** |
| 99 | + * Stops the peer connectivity manager. | ||
| 100 | + */ | ||
| 101 | + public void stop() { | ||
| 102 | + // TODO: Implement it | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + /** | ||
| 99 | * Sets up paths to establish connectivity between all internal | 106 | * Sets up paths to establish connectivity between all internal |
| 100 | * {@link BgpSpeaker}s and all external {@link BgpPeer}s. | 107 | * {@link BgpSpeaker}s and all external {@link BgpPeer}s. |
| 101 | */ | 108 | */ | ... | ... |
| ... | @@ -16,21 +16,16 @@ | ... | @@ -16,21 +16,16 @@ |
| 16 | package org.onlab.onos.sdnip; | 16 | package org.onlab.onos.sdnip; |
| 17 | 17 | ||
| 18 | import java.util.Collection; | 18 | import java.util.Collection; |
| 19 | -import java.util.HashMap; | ||
| 20 | import java.util.HashSet; | 19 | import java.util.HashSet; |
| 21 | import java.util.Iterator; | 20 | import java.util.Iterator; |
| 22 | import java.util.LinkedList; | 21 | import java.util.LinkedList; |
| 23 | import java.util.List; | 22 | import java.util.List; |
| 24 | -import java.util.Map; | ||
| 25 | import java.util.Set; | 23 | import java.util.Set; |
| 26 | import java.util.concurrent.BlockingQueue; | 24 | import java.util.concurrent.BlockingQueue; |
| 27 | -import java.util.concurrent.ConcurrentHashMap; | ||
| 28 | import java.util.concurrent.ExecutorService; | 25 | import java.util.concurrent.ExecutorService; |
| 29 | import java.util.concurrent.Executors; | 26 | import java.util.concurrent.Executors; |
| 30 | import java.util.concurrent.LinkedBlockingQueue; | 27 | import java.util.concurrent.LinkedBlockingQueue; |
| 31 | -import java.util.concurrent.Semaphore; | ||
| 32 | 28 | ||
| 33 | -import org.apache.commons.lang3.tuple.Pair; | ||
| 34 | import org.onlab.onos.core.ApplicationId; | 29 | import org.onlab.onos.core.ApplicationId; |
| 35 | import org.onlab.onos.net.ConnectPoint; | 30 | import org.onlab.onos.net.ConnectPoint; |
| 36 | import org.onlab.onos.net.Host; | 31 | import org.onlab.onos.net.Host; |
| ... | @@ -38,15 +33,9 @@ import org.onlab.onos.net.flow.DefaultTrafficSelector; | ... | @@ -38,15 +33,9 @@ import org.onlab.onos.net.flow.DefaultTrafficSelector; |
| 38 | import org.onlab.onos.net.flow.DefaultTrafficTreatment; | 33 | import org.onlab.onos.net.flow.DefaultTrafficTreatment; |
| 39 | import org.onlab.onos.net.flow.TrafficSelector; | 34 | import org.onlab.onos.net.flow.TrafficSelector; |
| 40 | import org.onlab.onos.net.flow.TrafficTreatment; | 35 | import org.onlab.onos.net.flow.TrafficTreatment; |
| 41 | -import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion; | ||
| 42 | -import org.onlab.onos.net.flow.criteria.Criterion; | ||
| 43 | -import org.onlab.onos.net.flow.criteria.Criterion.Type; | ||
| 44 | import org.onlab.onos.net.host.HostEvent; | 36 | import org.onlab.onos.net.host.HostEvent; |
| 45 | import org.onlab.onos.net.host.HostListener; | 37 | import org.onlab.onos.net.host.HostListener; |
| 46 | import org.onlab.onos.net.host.HostService; | 38 | import org.onlab.onos.net.host.HostService; |
| 47 | -import org.onlab.onos.net.intent.Intent; | ||
| 48 | -import org.onlab.onos.net.intent.IntentService; | ||
| 49 | -import org.onlab.onos.net.intent.IntentState; | ||
| 50 | import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; | 39 | import org.onlab.onos.net.intent.MultiPointToSinglePointIntent; |
| 51 | import org.onlab.onos.sdnip.config.BgpPeer; | 40 | import org.onlab.onos.sdnip.config.BgpPeer; |
| 52 | import org.onlab.onos.sdnip.config.Interface; | 41 | import org.onlab.onos.sdnip.config.Interface; |
| ... | @@ -59,7 +48,6 @@ import org.onlab.packet.MacAddress; | ... | @@ -59,7 +48,6 @@ import org.onlab.packet.MacAddress; |
| 59 | import org.slf4j.Logger; | 48 | import org.slf4j.Logger; |
| 60 | import org.slf4j.LoggerFactory; | 49 | import org.slf4j.LoggerFactory; |
| 61 | 50 | ||
| 62 | -import com.google.common.base.Objects; | ||
| 63 | import com.google.common.collect.HashMultimap; | 51 | import com.google.common.collect.HashMultimap; |
| 64 | import com.google.common.collect.Multimaps; | 52 | import com.google.common.collect.Multimaps; |
| 65 | import com.google.common.collect.SetMultimap; | 53 | import com.google.common.collect.SetMultimap; |
| ... | @@ -76,100 +64,81 @@ import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree; | ... | @@ -76,100 +64,81 @@ import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree; |
| 76 | public class Router implements RouteListener { | 64 | public class Router implements RouteListener { |
| 77 | 65 | ||
| 78 | private static final Logger log = LoggerFactory.getLogger(Router.class); | 66 | private static final Logger log = LoggerFactory.getLogger(Router.class); |
| 67 | + // For routes announced by local BGP daemon in SDN network, | ||
| 68 | + // the next hop will be 0.0.0.0. | ||
| 69 | + private static final Ip4Address LOCAL_NEXT_HOP = | ||
| 70 | + Ip4Address.valueOf("0.0.0.0"); | ||
| 79 | 71 | ||
| 80 | // Store all route updates in a radix tree. | 72 | // Store all route updates in a radix tree. |
| 81 | // The key in this tree is the binary string of prefix of the route. | 73 | // The key in this tree is the binary string of prefix of the route. |
| 82 | private InvertedRadixTree<RouteEntry> bgpRoutes; | 74 | private InvertedRadixTree<RouteEntry> bgpRoutes; |
| 83 | 75 | ||
| 84 | // Stores all incoming route updates in a queue. | 76 | // Stores all incoming route updates in a queue. |
| 85 | - private BlockingQueue<RouteUpdate> routeUpdates; | 77 | + private final BlockingQueue<RouteUpdate> routeUpdates; |
| 86 | 78 | ||
| 87 | // The Ip4Address is the next hop address of each route update. | 79 | // The Ip4Address is the next hop address of each route update. |
| 88 | - private SetMultimap<Ip4Address, RouteEntry> routesWaitingOnArp; | 80 | + private final SetMultimap<Ip4Address, RouteEntry> routesWaitingOnArp; |
| 89 | - private ConcurrentHashMap<Ip4Prefix, MultiPointToSinglePointIntent> pushedRouteIntents; | ||
| 90 | - | ||
| 91 | - private IntentService intentService; | ||
| 92 | - private HostService hostService; | ||
| 93 | - private SdnIpConfigService configService; | ||
| 94 | - private InterfaceService interfaceService; | ||
| 95 | - | ||
| 96 | - private ExecutorService bgpUpdatesExecutor; | ||
| 97 | - private ExecutorService bgpIntentsSynchronizerExecutor; | ||
| 98 | 81 | ||
| 99 | private final ApplicationId appId; | 82 | private final ApplicationId appId; |
| 100 | - | 83 | + private final IntentSynchronizer intentSynchronizer; |
| 101 | - // | 84 | + private final HostService hostService; |
| 102 | - // State to deal with SDN-IP Leader election and pushing Intents | 85 | + private final SdnIpConfigService configService; |
| 103 | - // | 86 | + private final InterfaceService interfaceService; |
| 104 | - private Semaphore intentsSynchronizerSemaphore = new Semaphore(0); | 87 | + private final ExecutorService bgpUpdatesExecutor; |
| 105 | - private volatile boolean isElectedLeader = false; | 88 | + private final HostListener hostListener; |
| 106 | - private volatile boolean isActivatedLeader = false; | ||
| 107 | - | ||
| 108 | - // For routes announced by local BGP daemon in SDN network, | ||
| 109 | - // the next hop will be 0.0.0.0. | ||
| 110 | - public static final Ip4Address LOCAL_NEXT_HOP = | ||
| 111 | - Ip4Address.valueOf("0.0.0.0"); | ||
| 112 | 89 | ||
| 113 | /** | 90 | /** |
| 114 | * Class constructor. | 91 | * Class constructor. |
| 115 | * | 92 | * |
| 116 | * @param appId the application ID | 93 | * @param appId the application ID |
| 117 | - * @param intentService the intent service | 94 | + * @param intentSynchronizer the intent synchronizer |
| 118 | * @param hostService the host service | 95 | * @param hostService the host service |
| 119 | * @param configService the configuration service | 96 | * @param configService the configuration service |
| 120 | * @param interfaceService the interface service | 97 | * @param interfaceService the interface service |
| 121 | */ | 98 | */ |
| 122 | - public Router(ApplicationId appId, IntentService intentService, | 99 | + public Router(ApplicationId appId, IntentSynchronizer intentSynchronizer, |
| 123 | HostService hostService, SdnIpConfigService configService, | 100 | HostService hostService, SdnIpConfigService configService, |
| 124 | InterfaceService interfaceService) { | 101 | InterfaceService interfaceService) { |
| 125 | this.appId = appId; | 102 | this.appId = appId; |
| 126 | - this.intentService = intentService; | 103 | + this.intentSynchronizer = intentSynchronizer; |
| 127 | this.hostService = hostService; | 104 | this.hostService = hostService; |
| 128 | this.configService = configService; | 105 | this.configService = configService; |
| 129 | this.interfaceService = interfaceService; | 106 | this.interfaceService = interfaceService; |
| 130 | 107 | ||
| 108 | + this.hostListener = new InternalHostListener(); | ||
| 109 | + | ||
| 131 | bgpRoutes = new ConcurrentInvertedRadixTree<>( | 110 | bgpRoutes = new ConcurrentInvertedRadixTree<>( |
| 132 | new DefaultByteArrayNodeFactory()); | 111 | new DefaultByteArrayNodeFactory()); |
| 133 | routeUpdates = new LinkedBlockingQueue<>(); | 112 | routeUpdates = new LinkedBlockingQueue<>(); |
| 134 | routesWaitingOnArp = Multimaps.synchronizedSetMultimap( | 113 | routesWaitingOnArp = Multimaps.synchronizedSetMultimap( |
| 135 | HashMultimap.<Ip4Address, RouteEntry>create()); | 114 | HashMultimap.<Ip4Address, RouteEntry>create()); |
| 136 | - pushedRouteIntents = new ConcurrentHashMap<>(); | ||
| 137 | 115 | ||
| 138 | bgpUpdatesExecutor = Executors.newSingleThreadExecutor( | 116 | bgpUpdatesExecutor = Executors.newSingleThreadExecutor( |
| 139 | new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build()); | 117 | new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build()); |
| 140 | - bgpIntentsSynchronizerExecutor = Executors.newSingleThreadExecutor( | ||
| 141 | - new ThreadFactoryBuilder() | ||
| 142 | - .setNameFormat("bgp-intents-synchronizer-%d").build()); | ||
| 143 | - | ||
| 144 | - this.hostService.addListener(new InternalHostListener()); | ||
| 145 | } | 118 | } |
| 146 | 119 | ||
| 147 | /** | 120 | /** |
| 148 | * Starts the router. | 121 | * Starts the router. |
| 149 | */ | 122 | */ |
| 150 | public void start() { | 123 | public void start() { |
| 124 | + this.hostService.addListener(hostListener); | ||
| 125 | + | ||
| 151 | bgpUpdatesExecutor.execute(new Runnable() { | 126 | bgpUpdatesExecutor.execute(new Runnable() { |
| 152 | @Override | 127 | @Override |
| 153 | public void run() { | 128 | public void run() { |
| 154 | doUpdatesThread(); | 129 | doUpdatesThread(); |
| 155 | } | 130 | } |
| 156 | }); | 131 | }); |
| 157 | - | ||
| 158 | - bgpIntentsSynchronizerExecutor.execute(new Runnable() { | ||
| 159 | - @Override | ||
| 160 | - public void run() { | ||
| 161 | - doIntentSynchronizationThread(); | ||
| 162 | - } | ||
| 163 | - }); | ||
| 164 | } | 132 | } |
| 165 | 133 | ||
| 166 | /** | 134 | /** |
| 167 | - * Shuts the router down. | 135 | + * Stops the router. |
| 168 | */ | 136 | */ |
| 169 | - public void shutdown() { | 137 | + public void stop() { |
| 170 | - // Stop all threads | 138 | + this.hostService.removeListener(hostListener); |
| 139 | + | ||
| 140 | + // Stop the thread(s) | ||
| 171 | bgpUpdatesExecutor.shutdownNow(); | 141 | bgpUpdatesExecutor.shutdownNow(); |
| 172 | - bgpIntentsSynchronizerExecutor.shutdownNow(); | ||
| 173 | 142 | ||
| 174 | synchronized (this) { | 143 | synchronized (this) { |
| 175 | // Cleanup all local state | 144 | // Cleanup all local state |
| ... | @@ -177,41 +146,7 @@ public class Router implements RouteListener { | ... | @@ -177,41 +146,7 @@ public class Router implements RouteListener { |
| 177 | new DefaultByteArrayNodeFactory()); | 146 | new DefaultByteArrayNodeFactory()); |
| 178 | routeUpdates.clear(); | 147 | routeUpdates.clear(); |
| 179 | routesWaitingOnArp.clear(); | 148 | routesWaitingOnArp.clear(); |
| 180 | - pushedRouteIntents.clear(); | ||
| 181 | - | ||
| 182 | - // | ||
| 183 | - // Withdraw all SDN-IP intents | ||
| 184 | - // | ||
| 185 | - if (!isElectedLeader) { | ||
| 186 | - return; // Nothing to do: not the leader anymore | ||
| 187 | - } | ||
| 188 | - log.debug("Withdrawing all SDN-IP Route Intents..."); | ||
| 189 | - for (Intent intent : intentService.getIntents()) { | ||
| 190 | - if (!(intent instanceof MultiPointToSinglePointIntent) | ||
| 191 | - || !intent.appId().equals(appId)) { | ||
| 192 | - continue; | ||
| 193 | - } | ||
| 194 | - intentService.withdraw(intent); | ||
| 195 | - } | ||
| 196 | - } | ||
| 197 | - } | ||
| 198 | - | ||
| 199 | - //@Override TODO hook this up to something | ||
| 200 | - public void leaderChanged(boolean isLeader) { | ||
| 201 | - log.debug("Leader changed: {}", isLeader); | ||
| 202 | - | ||
| 203 | - if (!isLeader) { | ||
| 204 | - this.isElectedLeader = false; | ||
| 205 | - this.isActivatedLeader = false; | ||
| 206 | - return; // Nothing to do | ||
| 207 | } | 149 | } |
| 208 | - this.isActivatedLeader = false; | ||
| 209 | - this.isElectedLeader = true; | ||
| 210 | - | ||
| 211 | - // | ||
| 212 | - // Tell the Intents Synchronizer thread to start the synchronization | ||
| 213 | - // | ||
| 214 | - intentsSynchronizerSemaphore.release(); | ||
| 215 | } | 150 | } |
| 216 | 151 | ||
| 217 | @Override | 152 | @Override |
| ... | @@ -227,35 +162,6 @@ public class Router implements RouteListener { | ... | @@ -227,35 +162,6 @@ public class Router implements RouteListener { |
| 227 | } | 162 | } |
| 228 | 163 | ||
| 229 | /** | 164 | /** |
| 230 | - * Thread for Intent Synchronization. | ||
| 231 | - */ | ||
| 232 | - private void doIntentSynchronizationThread() { | ||
| 233 | - boolean interrupted = false; | ||
| 234 | - try { | ||
| 235 | - while (!interrupted) { | ||
| 236 | - try { | ||
| 237 | - intentsSynchronizerSemaphore.acquire(); | ||
| 238 | - // | ||
| 239 | - // Drain all permits, because a single synchronization is | ||
| 240 | - // sufficient. | ||
| 241 | - // | ||
| 242 | - intentsSynchronizerSemaphore.drainPermits(); | ||
| 243 | - } catch (InterruptedException e) { | ||
| 244 | - log.debug("Interrupted while waiting to become " + | ||
| 245 | - "Intent Synchronization leader"); | ||
| 246 | - interrupted = true; | ||
| 247 | - break; | ||
| 248 | - } | ||
| 249 | - syncIntents(); | ||
| 250 | - } | ||
| 251 | - } finally { | ||
| 252 | - if (interrupted) { | ||
| 253 | - Thread.currentThread().interrupt(); | ||
| 254 | - } | ||
| 255 | - } | ||
| 256 | - } | ||
| 257 | - | ||
| 258 | - /** | ||
| 259 | * Thread for handling route updates. | 165 | * Thread for handling route updates. |
| 260 | */ | 166 | */ |
| 261 | private void doUpdatesThread() { | 167 | private void doUpdatesThread() { |
| ... | @@ -290,194 +196,6 @@ public class Router implements RouteListener { | ... | @@ -290,194 +196,6 @@ public class Router implements RouteListener { |
| 290 | } | 196 | } |
| 291 | 197 | ||
| 292 | /** | 198 | /** |
| 293 | - * Performs Intents Synchronization between the internally stored Route | ||
| 294 | - * Intents and the installed Route Intents. | ||
| 295 | - */ | ||
| 296 | - private void syncIntents() { | ||
| 297 | - synchronized (this) { | ||
| 298 | - if (!isElectedLeader) { | ||
| 299 | - return; // Nothing to do: not the leader anymore | ||
| 300 | - } | ||
| 301 | - log.debug("Syncing SDN-IP Route Intents..."); | ||
| 302 | - | ||
| 303 | - Map<Ip4Prefix, MultiPointToSinglePointIntent> fetchedIntents = | ||
| 304 | - new HashMap<>(); | ||
| 305 | - | ||
| 306 | - // | ||
| 307 | - // Fetch all intents, and classify the Multi-Point-to-Point Intents | ||
| 308 | - // based on the matching prefix. | ||
| 309 | - // | ||
| 310 | - for (Intent intent : intentService.getIntents()) { | ||
| 311 | - | ||
| 312 | - if (!(intent instanceof MultiPointToSinglePointIntent) | ||
| 313 | - || !intent.appId().equals(appId)) { | ||
| 314 | - continue; | ||
| 315 | - } | ||
| 316 | - MultiPointToSinglePointIntent mp2pIntent = | ||
| 317 | - (MultiPointToSinglePointIntent) intent; | ||
| 318 | - | ||
| 319 | - Criterion c = mp2pIntent.selector().getCriterion(Type.IPV4_DST); | ||
| 320 | - if (c != null && c instanceof IPCriterion) { | ||
| 321 | - IPCriterion ipCriterion = (IPCriterion) c; | ||
| 322 | - Ip4Prefix ip4Prefix = ipCriterion.ip().getIp4Prefix(); | ||
| 323 | - if (ip4Prefix == null) { | ||
| 324 | - // TODO: For now we support only IPv4 | ||
| 325 | - continue; | ||
| 326 | - } | ||
| 327 | - fetchedIntents.put(ip4Prefix, mp2pIntent); | ||
| 328 | - } else { | ||
| 329 | - log.warn("No IPV4_DST criterion found for intent {}", | ||
| 330 | - mp2pIntent.id()); | ||
| 331 | - } | ||
| 332 | - | ||
| 333 | - } | ||
| 334 | - | ||
| 335 | - // | ||
| 336 | - // Compare for each prefix the local IN-MEMORY Intents with the | ||
| 337 | - // FETCHED Intents: | ||
| 338 | - // - If the IN-MEMORY Intent is same as the FETCHED Intent, store | ||
| 339 | - // the FETCHED Intent in the local memory (i.e., override the | ||
| 340 | - // IN-MEMORY Intent) to preserve the original Intent ID | ||
| 341 | - // - if the IN-MEMORY Intent is not same as the FETCHED Intent, | ||
| 342 | - // delete the FETCHED Intent, and push/install the IN-MEMORY | ||
| 343 | - // Intent. | ||
| 344 | - // - If there is an IN-MEMORY Intent for a prefix, but no FETCHED | ||
| 345 | - // Intent for same prefix, then push/install the IN-MEMORY | ||
| 346 | - // Intent. | ||
| 347 | - // - If there is a FETCHED Intent for a prefix, but no IN-MEMORY | ||
| 348 | - // Intent for same prefix, then delete/withdraw the FETCHED | ||
| 349 | - // Intent. | ||
| 350 | - // | ||
| 351 | - Collection<Pair<Ip4Prefix, MultiPointToSinglePointIntent>> | ||
| 352 | - storeInMemoryIntents = new LinkedList<>(); | ||
| 353 | - Collection<Pair<Ip4Prefix, MultiPointToSinglePointIntent>> | ||
| 354 | - addIntents = new LinkedList<>(); | ||
| 355 | - Collection<Pair<Ip4Prefix, MultiPointToSinglePointIntent>> | ||
| 356 | - deleteIntents = new LinkedList<>(); | ||
| 357 | - for (Map.Entry<Ip4Prefix, MultiPointToSinglePointIntent> entry : | ||
| 358 | - pushedRouteIntents.entrySet()) { | ||
| 359 | - Ip4Prefix prefix = entry.getKey(); | ||
| 360 | - MultiPointToSinglePointIntent inMemoryIntent = | ||
| 361 | - entry.getValue(); | ||
| 362 | - MultiPointToSinglePointIntent fetchedIntent = | ||
| 363 | - fetchedIntents.get(prefix); | ||
| 364 | - | ||
| 365 | - if (fetchedIntent == null) { | ||
| 366 | - // | ||
| 367 | - // No FETCHED Intent for same prefix: push the IN-MEMORY | ||
| 368 | - // Intent. | ||
| 369 | - // | ||
| 370 | - addIntents.add(Pair.of(prefix, inMemoryIntent)); | ||
| 371 | - continue; | ||
| 372 | - } | ||
| 373 | - | ||
| 374 | - IntentState state = intentService.getIntentState(fetchedIntent.id()); | ||
| 375 | - if (state == IntentState.WITHDRAWING || | ||
| 376 | - state == IntentState.WITHDRAWN) { | ||
| 377 | - // The intent has been withdrawn but according to our route | ||
| 378 | - // table it should be installed. We'll reinstall it. | ||
| 379 | - addIntents.add(Pair.of(prefix, inMemoryIntent)); | ||
| 380 | - } | ||
| 381 | - | ||
| 382 | - // | ||
| 383 | - // If IN-MEMORY Intent is same as the FETCHED Intent, | ||
| 384 | - // store the FETCHED Intent in the local memory. | ||
| 385 | - // | ||
| 386 | - if (compareMultiPointToSinglePointIntents(inMemoryIntent, | ||
| 387 | - fetchedIntent)) { | ||
| 388 | - storeInMemoryIntents.add(Pair.of(prefix, fetchedIntent)); | ||
| 389 | - } else { | ||
| 390 | - // | ||
| 391 | - // The IN-MEMORY Intent is not same as the FETCHED Intent, | ||
| 392 | - // hence delete the FETCHED Intent, and install the | ||
| 393 | - // IN-MEMORY Intent. | ||
| 394 | - // | ||
| 395 | - deleteIntents.add(Pair.of(prefix, fetchedIntent)); | ||
| 396 | - addIntents.add(Pair.of(prefix, inMemoryIntent)); | ||
| 397 | - } | ||
| 398 | - fetchedIntents.remove(prefix); | ||
| 399 | - } | ||
| 400 | - | ||
| 401 | - // | ||
| 402 | - // Any remaining FETCHED Intents have to be deleted/withdrawn | ||
| 403 | - // | ||
| 404 | - for (Map.Entry<Ip4Prefix, MultiPointToSinglePointIntent> entry : | ||
| 405 | - fetchedIntents.entrySet()) { | ||
| 406 | - Ip4Prefix prefix = entry.getKey(); | ||
| 407 | - MultiPointToSinglePointIntent fetchedIntent = entry.getValue(); | ||
| 408 | - deleteIntents.add(Pair.of(prefix, fetchedIntent)); | ||
| 409 | - } | ||
| 410 | - | ||
| 411 | - // | ||
| 412 | - // Perform the actions: | ||
| 413 | - // 1. Store in memory fetched intents that are same. Can be done | ||
| 414 | - // even if we are not the leader anymore | ||
| 415 | - // 2. Delete intents: check if the leader before each operation | ||
| 416 | - // 3. Add intents: check if the leader before each operation | ||
| 417 | - // | ||
| 418 | - for (Pair<Ip4Prefix, MultiPointToSinglePointIntent> pair : | ||
| 419 | - storeInMemoryIntents) { | ||
| 420 | - Ip4Prefix prefix = pair.getLeft(); | ||
| 421 | - MultiPointToSinglePointIntent intent = pair.getRight(); | ||
| 422 | - log.debug("Intent synchronization: updating in-memory " + | ||
| 423 | - "Intent for prefix: {}", prefix); | ||
| 424 | - pushedRouteIntents.put(prefix, intent); | ||
| 425 | - } | ||
| 426 | - // | ||
| 427 | - isActivatedLeader = true; // Allow push of Intents | ||
| 428 | - for (Pair<Ip4Prefix, MultiPointToSinglePointIntent> pair : | ||
| 429 | - deleteIntents) { | ||
| 430 | - Ip4Prefix prefix = pair.getLeft(); | ||
| 431 | - MultiPointToSinglePointIntent intent = pair.getRight(); | ||
| 432 | - if (!isElectedLeader) { | ||
| 433 | - isActivatedLeader = false; | ||
| 434 | - return; | ||
| 435 | - } | ||
| 436 | - log.debug("Intent synchronization: deleting Intent for " + | ||
| 437 | - "prefix: {}", prefix); | ||
| 438 | - intentService.withdraw(intent); | ||
| 439 | - } | ||
| 440 | - // | ||
| 441 | - for (Pair<Ip4Prefix, MultiPointToSinglePointIntent> pair : | ||
| 442 | - addIntents) { | ||
| 443 | - Ip4Prefix prefix = pair.getLeft(); | ||
| 444 | - MultiPointToSinglePointIntent intent = pair.getRight(); | ||
| 445 | - if (!isElectedLeader) { | ||
| 446 | - isActivatedLeader = false; | ||
| 447 | - return; | ||
| 448 | - } | ||
| 449 | - log.debug("Intent synchronization: adding Intent for " + | ||
| 450 | - "prefix: {}", prefix); | ||
| 451 | - intentService.submit(intent); | ||
| 452 | - } | ||
| 453 | - if (!isElectedLeader) { | ||
| 454 | - isActivatedLeader = false; | ||
| 455 | - } | ||
| 456 | - log.debug("Syncing SDN-IP routes completed."); | ||
| 457 | - } | ||
| 458 | - } | ||
| 459 | - | ||
| 460 | - /** | ||
| 461 | - * Compares two Multi-point to Single Point Intents whether they represent | ||
| 462 | - * same logical intention. | ||
| 463 | - * | ||
| 464 | - * @param intent1 the first Intent to compare | ||
| 465 | - * @param intent2 the second Intent to compare | ||
| 466 | - * @return true if both Intents represent same logical intention, otherwise | ||
| 467 | - * false | ||
| 468 | - */ | ||
| 469 | - private boolean compareMultiPointToSinglePointIntents( | ||
| 470 | - MultiPointToSinglePointIntent intent1, | ||
| 471 | - MultiPointToSinglePointIntent intent2) { | ||
| 472 | - | ||
| 473 | - return Objects.equal(intent1.appId(), intent2.appId()) && | ||
| 474 | - Objects.equal(intent1.selector(), intent2.selector()) && | ||
| 475 | - Objects.equal(intent1.treatment(), intent2.treatment()) && | ||
| 476 | - Objects.equal(intent1.ingressPoints(), intent2.ingressPoints()) && | ||
| 477 | - Objects.equal(intent1.egressPoint(), intent2.egressPoint()); | ||
| 478 | - } | ||
| 479 | - | ||
| 480 | - /** | ||
| 481 | * Processes adding a route entry. | 199 | * Processes adding a route entry. |
| 482 | * <p> | 200 | * <p> |
| 483 | * Put new route entry into the radix tree. If there was an existing | 201 | * Put new route entry into the radix tree. If there was an existing |
| ... | @@ -488,7 +206,7 @@ public class Router implements RouteListener { | ... | @@ -488,7 +206,7 @@ public class Router implements RouteListener { |
| 488 | * | 206 | * |
| 489 | * @param routeEntry the route entry to add | 207 | * @param routeEntry the route entry to add |
| 490 | */ | 208 | */ |
| 491 | - protected void processRouteAdd(RouteEntry routeEntry) { | 209 | + void processRouteAdd(RouteEntry routeEntry) { |
| 492 | synchronized (this) { | 210 | synchronized (this) { |
| 493 | log.debug("Processing route add: {}", routeEntry); | 211 | log.debug("Processing route add: {}", routeEntry); |
| 494 | 212 | ||
| ... | @@ -610,17 +328,8 @@ public class Router implements RouteListener { | ... | @@ -610,17 +328,8 @@ public class Router implements RouteListener { |
| 610 | log.debug("Adding intent for prefix {}, next hop mac {}", | 328 | log.debug("Adding intent for prefix {}, next hop mac {}", |
| 611 | prefix, nextHopMacAddress); | 329 | prefix, nextHopMacAddress); |
| 612 | 330 | ||
| 613 | - MultiPointToSinglePointIntent pushedIntent = | ||
| 614 | - pushedRouteIntents.get(prefix); | ||
| 615 | - | ||
| 616 | - // Just for testing. | ||
| 617 | - if (pushedIntent != null) { | ||
| 618 | - log.error("There should not be a pushed intent: {}", pushedIntent); | ||
| 619 | - } | ||
| 620 | - | ||
| 621 | - ConnectPoint egressPort = egressInterface.connectPoint(); | ||
| 622 | - | ||
| 623 | Set<ConnectPoint> ingressPorts = new HashSet<>(); | 331 | Set<ConnectPoint> ingressPorts = new HashSet<>(); |
| 332 | + ConnectPoint egressPort = egressInterface.connectPoint(); | ||
| 624 | 333 | ||
| 625 | for (Interface intf : interfaceService.getInterfaces()) { | 334 | for (Interface intf : interfaceService.getInterfaces()) { |
| 626 | if (!intf.connectPoint().equals(egressInterface.connectPoint())) { | 335 | if (!intf.connectPoint().equals(egressInterface.connectPoint())) { |
| ... | @@ -644,14 +353,7 @@ public class Router implements RouteListener { | ... | @@ -644,14 +353,7 @@ public class Router implements RouteListener { |
| 644 | new MultiPointToSinglePointIntent(appId, selector, treatment, | 353 | new MultiPointToSinglePointIntent(appId, selector, treatment, |
| 645 | ingressPorts, egressPort); | 354 | ingressPorts, egressPort); |
| 646 | 355 | ||
| 647 | - if (isElectedLeader && isActivatedLeader) { | 356 | + intentSynchronizer.submitRouteIntent(prefix, intent); |
| 648 | - log.debug("Intent installation: adding Intent for prefix: {}", | ||
| 649 | - prefix); | ||
| 650 | - intentService.submit(intent); | ||
| 651 | - } | ||
| 652 | - | ||
| 653 | - // Maintain the Intent | ||
| 654 | - pushedRouteIntents.put(prefix, intent); | ||
| 655 | } | 357 | } |
| 656 | 358 | ||
| 657 | /** | 359 | /** |
| ... | @@ -663,7 +365,7 @@ public class Router implements RouteListener { | ... | @@ -663,7 +365,7 @@ public class Router implements RouteListener { |
| 663 | * | 365 | * |
| 664 | * @param routeEntry the route entry to delete | 366 | * @param routeEntry the route entry to delete |
| 665 | */ | 367 | */ |
| 666 | - protected void processRouteDelete(RouteEntry routeEntry) { | 368 | + void processRouteDelete(RouteEntry routeEntry) { |
| 667 | synchronized (this) { | 369 | synchronized (this) { |
| 668 | log.debug("Processing route delete: {}", routeEntry); | 370 | log.debug("Processing route delete: {}", routeEntry); |
| 669 | Ip4Prefix prefix = routeEntry.prefix(); | 371 | Ip4Prefix prefix = routeEntry.prefix(); |
| ... | @@ -691,21 +393,7 @@ public class Router implements RouteListener { | ... | @@ -691,21 +393,7 @@ public class Router implements RouteListener { |
| 691 | private void executeRouteDelete(RouteEntry routeEntry) { | 393 | private void executeRouteDelete(RouteEntry routeEntry) { |
| 692 | log.debug("Executing route delete: {}", routeEntry); | 394 | log.debug("Executing route delete: {}", routeEntry); |
| 693 | 395 | ||
| 694 | - Ip4Prefix prefix = routeEntry.prefix(); | 396 | + intentSynchronizer.withdrawRouteIntent(routeEntry.prefix()); |
| 695 | - | ||
| 696 | - MultiPointToSinglePointIntent intent = | ||
| 697 | - pushedRouteIntents.remove(prefix); | ||
| 698 | - | ||
| 699 | - if (intent == null) { | ||
| 700 | - log.debug("There is no intent in pushedRouteIntents to delete " + | ||
| 701 | - "for prefix: {}", prefix); | ||
| 702 | - } else { | ||
| 703 | - if (isElectedLeader && isActivatedLeader) { | ||
| 704 | - log.debug("Intent installation: deleting Intent for prefix: {}", | ||
| 705 | - prefix); | ||
| 706 | - intentService.withdraw(intent); | ||
| 707 | - } | ||
| 708 | - } | ||
| 709 | } | 397 | } |
| 710 | 398 | ||
| 711 | /** | 399 | /** |
| ... | @@ -774,21 +462,6 @@ public class Router implements RouteListener { | ... | @@ -774,21 +462,6 @@ public class Router implements RouteListener { |
| 774 | } | 462 | } |
| 775 | 463 | ||
| 776 | /** | 464 | /** |
| 777 | - * Gets the pushed route intents. | ||
| 778 | - * | ||
| 779 | - * @return the pushed route intents | ||
| 780 | - */ | ||
| 781 | - public Collection<MultiPointToSinglePointIntent> getPushedRouteIntents() { | ||
| 782 | - List<MultiPointToSinglePointIntent> pushedIntents = new LinkedList<>(); | ||
| 783 | - | ||
| 784 | - for (Map.Entry<Ip4Prefix, MultiPointToSinglePointIntent> entry : | ||
| 785 | - pushedRouteIntents.entrySet()) { | ||
| 786 | - pushedIntents.add(entry.getValue()); | ||
| 787 | - } | ||
| 788 | - return pushedIntents; | ||
| 789 | - } | ||
| 790 | - | ||
| 791 | - /** | ||
| 792 | * Listener for host events. | 465 | * Listener for host events. |
| 793 | */ | 466 | */ |
| 794 | class InternalHostListener implements HostListener { | 467 | class InternalHostListener implements HostListener { | ... | ... |
| ... | @@ -55,6 +55,7 @@ public class SdnIp implements SdnIpService { | ... | @@ -55,6 +55,7 @@ public class SdnIp implements SdnIpService { |
| 55 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 55 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 56 | protected HostService hostService; | 56 | protected HostService hostService; |
| 57 | 57 | ||
| 58 | + private IntentSynchronizer intentSynchronizer; | ||
| 58 | private SdnIpConfigReader config; | 59 | private SdnIpConfigReader config; |
| 59 | private PeerConnectivityManager peerConnectivity; | 60 | private PeerConnectivityManager peerConnectivity; |
| 60 | private Router router; | 61 | private Router router; |
| ... | @@ -64,35 +65,41 @@ public class SdnIp implements SdnIpService { | ... | @@ -64,35 +65,41 @@ public class SdnIp implements SdnIpService { |
| 64 | protected void activate() { | 65 | protected void activate() { |
| 65 | log.debug("SDN-IP started"); | 66 | log.debug("SDN-IP started"); |
| 66 | 67 | ||
| 68 | + ApplicationId appId = coreService.registerApplication(SDN_IP_APP); | ||
| 67 | config = new SdnIpConfigReader(); | 69 | config = new SdnIpConfigReader(); |
| 68 | config.init(); | 70 | config.init(); |
| 69 | 71 | ||
| 70 | - InterfaceService interfaceService = new HostToInterfaceAdaptor(hostService); | 72 | + InterfaceService interfaceService = |
| 73 | + new HostToInterfaceAdaptor(hostService); | ||
| 71 | 74 | ||
| 72 | - ApplicationId appId = coreService.registerApplication(SDN_IP_APP); | 75 | + intentSynchronizer = new IntentSynchronizer(appId, intentService); |
| 76 | + intentSynchronizer.start(); | ||
| 73 | 77 | ||
| 74 | peerConnectivity = new PeerConnectivityManager(appId, config, | 78 | peerConnectivity = new PeerConnectivityManager(appId, config, |
| 75 | interfaceService, intentService); | 79 | interfaceService, intentService); |
| 76 | peerConnectivity.start(); | 80 | peerConnectivity.start(); |
| 77 | 81 | ||
| 78 | - router = new Router(appId, intentService, hostService, config, interfaceService); | 82 | + router = new Router(appId, intentSynchronizer, hostService, config, |
| 83 | + interfaceService); | ||
| 79 | router.start(); | 84 | router.start(); |
| 80 | 85 | ||
| 81 | - // Manually set the router as the leader to allow testing | 86 | + // Manually set the instance as the leader to allow testing |
| 82 | // TODO change this when we get a leader election | 87 | // TODO change this when we get a leader election |
| 83 | - router.leaderChanged(true); | 88 | + intentSynchronizer.leaderChanged(true); |
| 84 | 89 | ||
| 85 | bgpSessionManager = new BgpSessionManager(router); | 90 | bgpSessionManager = new BgpSessionManager(router); |
| 86 | - bgpSessionManager.startUp(2000); // TODO | 91 | + // TODO: the local BGP listen port number should be configurable |
| 92 | + bgpSessionManager.start(2000); | ||
| 87 | 93 | ||
| 88 | // TODO need to disable link discovery on external ports | 94 | // TODO need to disable link discovery on external ports |
| 89 | - | ||
| 90 | } | 95 | } |
| 91 | 96 | ||
| 92 | @Deactivate | 97 | @Deactivate |
| 93 | protected void deactivate() { | 98 | protected void deactivate() { |
| 94 | - bgpSessionManager.shutDown(); | 99 | + bgpSessionManager.stop(); |
| 95 | - router.shutdown(); | 100 | + router.stop(); |
| 101 | + peerConnectivity.stop(); | ||
| 102 | + intentSynchronizer.stop(); | ||
| 96 | 103 | ||
| 97 | log.info("Stopped"); | 104 | log.info("Stopped"); |
| 98 | } | 105 | } |
| ... | @@ -114,7 +121,7 @@ public class SdnIp implements SdnIpService { | ... | @@ -114,7 +121,7 @@ public class SdnIp implements SdnIpService { |
| 114 | 121 | ||
| 115 | @Override | 122 | @Override |
| 116 | public void modifyPrimary(boolean isPrimary) { | 123 | public void modifyPrimary(boolean isPrimary) { |
| 117 | - router.leaderChanged(isPrimary); | 124 | + intentSynchronizer.leaderChanged(isPrimary); |
| 118 | } | 125 | } |
| 119 | 126 | ||
| 120 | static String dpidToUri(String dpid) { | 127 | static String dpidToUri(String dpid) { | ... | ... |
| ... | @@ -181,8 +181,8 @@ public class BgpSessionManager { | ... | @@ -181,8 +181,8 @@ public class BgpSessionManager { |
| 181 | * @param listenPortNumber the port number to listen on. By default | 181 | * @param listenPortNumber the port number to listen on. By default |
| 182 | * it should be BgpConstants.BGP_PORT (179) | 182 | * it should be BgpConstants.BGP_PORT (179) |
| 183 | */ | 183 | */ |
| 184 | - public void startUp(int listenPortNumber) { | 184 | + public void start(int listenPortNumber) { |
| 185 | - log.debug("BGP Session Manager startUp()"); | 185 | + log.debug("BGP Session Manager start."); |
| 186 | isShutdown = false; | 186 | isShutdown = false; |
| 187 | 187 | ||
| 188 | ChannelFactory channelFactory = | 188 | ChannelFactory channelFactory = |
| ... | @@ -222,9 +222,9 @@ public class BgpSessionManager { | ... | @@ -222,9 +222,9 @@ public class BgpSessionManager { |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | /** | 224 | /** |
| 225 | - * Shuts down the BGP Session Manager operation. | 225 | + * Stops the BGP Session Manager operation. |
| 226 | */ | 226 | */ |
| 227 | - public void shutDown() { | 227 | + public void stop() { |
| 228 | isShutdown = true; | 228 | isShutdown = true; |
| 229 | allChannels.close().awaitUninterruptibly(); | 229 | allChannels.close().awaitUninterruptibly(); |
| 230 | serverBootstrap.releaseExternalResources(); | 230 | serverBootstrap.releaseExternalResources(); | ... | ... |
| ... | @@ -54,7 +54,8 @@ import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree; | ... | @@ -54,7 +54,8 @@ import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree; |
| 54 | import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree; | 54 | import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree; |
| 55 | 55 | ||
| 56 | /** | 56 | /** |
| 57 | - * This class tests the intent synchronization function in Router class. | 57 | + * This class tests the intent synchronization function in the |
| 58 | + * IntentSynchronizer class. | ||
| 58 | */ | 59 | */ |
| 59 | public class IntentSyncTest { | 60 | public class IntentSyncTest { |
| 60 | 61 | ||
| ... | @@ -74,6 +75,7 @@ public class IntentSyncTest { | ... | @@ -74,6 +75,7 @@ public class IntentSyncTest { |
| 74 | DeviceId.deviceId("of:0000000000000003"), | 75 | DeviceId.deviceId("of:0000000000000003"), |
| 75 | PortNumber.portNumber(1)); | 76 | PortNumber.portNumber(1)); |
| 76 | 77 | ||
| 78 | + private IntentSynchronizer intentSynchronizer; | ||
| 77 | private Router router; | 79 | private Router router; |
| 78 | 80 | ||
| 79 | private static final ApplicationId APPID = new ApplicationId() { | 81 | private static final ApplicationId APPID = new ApplicationId() { |
| ... | @@ -94,7 +96,8 @@ public class IntentSyncTest { | ... | @@ -94,7 +96,8 @@ public class IntentSyncTest { |
| 94 | setUpHostService(); | 96 | setUpHostService(); |
| 95 | intentService = createMock(IntentService.class); | 97 | intentService = createMock(IntentService.class); |
| 96 | 98 | ||
| 97 | - router = new Router(APPID, intentService, | 99 | + intentSynchronizer = new IntentSynchronizer(APPID, intentService); |
| 100 | + router = new Router(APPID, intentSynchronizer, | ||
| 98 | hostService, null, interfaceService); | 101 | hostService, null, interfaceService); |
| 99 | } | 102 | } |
| 100 | 103 | ||
| ... | @@ -260,7 +263,7 @@ public class IntentSyncTest { | ... | @@ -260,7 +263,7 @@ public class IntentSyncTest { |
| 260 | // Compose a intent, which is equal to intent5 but the id is different. | 263 | // Compose a intent, which is equal to intent5 but the id is different. |
| 261 | MultiPointToSinglePointIntent intent5New = | 264 | MultiPointToSinglePointIntent intent5New = |
| 262 | staticIntentBuilder(intent5, routeEntry5, "00:00:00:00:00:01"); | 265 | staticIntentBuilder(intent5, routeEntry5, "00:00:00:00:00:01"); |
| 263 | - assertTrue(TestUtils.callMethod(router, | 266 | + assertTrue(TestUtils.callMethod(intentSynchronizer, |
| 264 | "compareMultiPointToSinglePointIntents", | 267 | "compareMultiPointToSinglePointIntents", |
| 265 | new Class<?>[] {MultiPointToSinglePointIntent.class, | 268 | new Class<?>[] {MultiPointToSinglePointIntent.class, |
| 266 | MultiPointToSinglePointIntent.class}, | 269 | MultiPointToSinglePointIntent.class}, |
| ... | @@ -296,7 +299,8 @@ public class IntentSyncTest { | ... | @@ -296,7 +299,8 @@ public class IntentSyncTest { |
| 296 | pushedRouteIntents.put(routeEntry5.prefix(), intent5New); | 299 | pushedRouteIntents.put(routeEntry5.prefix(), intent5New); |
| 297 | pushedRouteIntents.put(routeEntry6.prefix(), intent6); | 300 | pushedRouteIntents.put(routeEntry6.prefix(), intent6); |
| 298 | pushedRouteIntents.put(routeEntry7.prefix(), intent7); | 301 | pushedRouteIntents.put(routeEntry7.prefix(), intent7); |
| 299 | - TestUtils.setField(router, "pushedRouteIntents", pushedRouteIntents); | 302 | + TestUtils.setField(intentSynchronizer, "pushedRouteIntents", |
| 303 | + pushedRouteIntents); | ||
| 300 | 304 | ||
| 301 | // Set up expectation | 305 | // Set up expectation |
| 302 | reset(intentService); | 306 | reset(intentService); |
| ... | @@ -327,8 +331,9 @@ public class IntentSyncTest { | ... | @@ -327,8 +331,9 @@ public class IntentSyncTest { |
| 327 | replay(intentService); | 331 | replay(intentService); |
| 328 | 332 | ||
| 329 | // Start the test | 333 | // Start the test |
| 330 | - router.leaderChanged(true); | 334 | + intentSynchronizer.leaderChanged(true); |
| 331 | - TestUtils.callMethod(router, "syncIntents", new Class<?>[] {}); | 335 | + TestUtils.callMethod(intentSynchronizer, "syncIntents", |
| 336 | + new Class<?>[] {}); | ||
| 332 | 337 | ||
| 333 | // Verify | 338 | // Verify |
| 334 | assertEquals(router.getRoutes().size(), 6); | 339 | assertEquals(router.getRoutes().size(), 6); |
| ... | @@ -338,12 +343,12 @@ public class IntentSyncTest { | ... | @@ -338,12 +343,12 @@ public class IntentSyncTest { |
| 338 | assertTrue(router.getRoutes().contains(routeEntry5)); | 343 | assertTrue(router.getRoutes().contains(routeEntry5)); |
| 339 | assertTrue(router.getRoutes().contains(routeEntry6)); | 344 | assertTrue(router.getRoutes().contains(routeEntry6)); |
| 340 | 345 | ||
| 341 | - assertEquals(router.getPushedRouteIntents().size(), 6); | 346 | + assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 6); |
| 342 | - assertTrue(router.getPushedRouteIntents().contains(intent1)); | 347 | + assertTrue(intentSynchronizer.getPushedRouteIntents().contains(intent1)); |
| 343 | - assertTrue(router.getPushedRouteIntents().contains(intent3)); | 348 | + assertTrue(intentSynchronizer.getPushedRouteIntents().contains(intent3)); |
| 344 | - assertTrue(router.getPushedRouteIntents().contains(intent4Update)); | 349 | + assertTrue(intentSynchronizer.getPushedRouteIntents().contains(intent4Update)); |
| 345 | - assertTrue(router.getPushedRouteIntents().contains(intent5)); | 350 | + assertTrue(intentSynchronizer.getPushedRouteIntents().contains(intent5)); |
| 346 | - assertTrue(router.getPushedRouteIntents().contains(intent6)); | 351 | + assertTrue(intentSynchronizer.getPushedRouteIntents().contains(intent6)); |
| 347 | 352 | ||
| 348 | verify(intentService); | 353 | verify(intentService); |
| 349 | } | 354 | } | ... | ... |
| ... | @@ -102,6 +102,7 @@ public class RouterTest { | ... | @@ -102,6 +102,7 @@ public class RouterTest { |
| 102 | } | 102 | } |
| 103 | }; | 103 | }; |
| 104 | 104 | ||
| 105 | + private IntentSynchronizer intentSynchronizer; | ||
| 105 | private Router router; | 106 | private Router router; |
| 106 | 107 | ||
| 107 | @Before | 108 | @Before |
| ... | @@ -113,7 +114,8 @@ public class RouterTest { | ... | @@ -113,7 +114,8 @@ public class RouterTest { |
| 113 | 114 | ||
| 114 | intentService = createMock(IntentService.class); | 115 | intentService = createMock(IntentService.class); |
| 115 | 116 | ||
| 116 | - router = new Router(APPID, intentService, | 117 | + intentSynchronizer = new IntentSynchronizer(APPID, intentService); |
| 118 | + router = new Router(APPID, intentSynchronizer, | ||
| 117 | hostService, sdnIpConfigService, interfaceService); | 119 | hostService, sdnIpConfigService, interfaceService); |
| 118 | } | 120 | } |
| 119 | 121 | ||
| ... | @@ -258,15 +260,15 @@ public class RouterTest { | ... | @@ -258,15 +260,15 @@ public class RouterTest { |
| 258 | replay(intentService); | 260 | replay(intentService); |
| 259 | 261 | ||
| 260 | // Call the processRouteAdd() method in Router class | 262 | // Call the processRouteAdd() method in Router class |
| 261 | - router.leaderChanged(true); | 263 | + intentSynchronizer.leaderChanged(true); |
| 262 | - TestUtils.setField(router, "isActivatedLeader", true); | 264 | + TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); |
| 263 | router.processRouteAdd(routeEntry); | 265 | router.processRouteAdd(routeEntry); |
| 264 | 266 | ||
| 265 | // Verify | 267 | // Verify |
| 266 | assertEquals(router.getRoutes().size(), 1); | 268 | assertEquals(router.getRoutes().size(), 1); |
| 267 | assertTrue(router.getRoutes().contains(routeEntry)); | 269 | assertTrue(router.getRoutes().contains(routeEntry)); |
| 268 | - assertEquals(router.getPushedRouteIntents().size(), 1); | 270 | + assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 1); |
| 269 | - assertEquals(router.getPushedRouteIntents().iterator().next(), | 271 | + assertEquals(intentSynchronizer.getPushedRouteIntents().iterator().next(), |
| 270 | intent); | 272 | intent); |
| 271 | verify(intentService); | 273 | verify(intentService); |
| 272 | } | 274 | } |
| ... | @@ -338,15 +340,15 @@ public class RouterTest { | ... | @@ -338,15 +340,15 @@ public class RouterTest { |
| 338 | replay(intentService); | 340 | replay(intentService); |
| 339 | 341 | ||
| 340 | // Call the processRouteAdd() method in Router class | 342 | // Call the processRouteAdd() method in Router class |
| 341 | - router.leaderChanged(true); | 343 | + intentSynchronizer.leaderChanged(true); |
| 342 | - TestUtils.setField(router, "isActivatedLeader", true); | 344 | + TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); |
| 343 | router.processRouteAdd(routeEntryUpdate); | 345 | router.processRouteAdd(routeEntryUpdate); |
| 344 | 346 | ||
| 345 | // Verify | 347 | // Verify |
| 346 | assertEquals(router.getRoutes().size(), 1); | 348 | assertEquals(router.getRoutes().size(), 1); |
| 347 | assertTrue(router.getRoutes().contains(routeEntryUpdate)); | 349 | assertTrue(router.getRoutes().contains(routeEntryUpdate)); |
| 348 | - assertEquals(router.getPushedRouteIntents().size(), 1); | 350 | + assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 1); |
| 349 | - assertEquals(router.getPushedRouteIntents().iterator().next(), | 351 | + assertEquals(intentSynchronizer.getPushedRouteIntents().iterator().next(), |
| 350 | intentNew); | 352 | intentNew); |
| 351 | verify(intentService); | 353 | verify(intentService); |
| 352 | } | 354 | } |
| ... | @@ -389,13 +391,13 @@ public class RouterTest { | ... | @@ -389,13 +391,13 @@ public class RouterTest { |
| 389 | replay(intentService); | 391 | replay(intentService); |
| 390 | 392 | ||
| 391 | // Call route deleting method in Router class | 393 | // Call route deleting method in Router class |
| 392 | - router.leaderChanged(true); | 394 | + intentSynchronizer.leaderChanged(true); |
| 393 | - TestUtils.setField(router, "isActivatedLeader", true); | 395 | + TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); |
| 394 | router.processRouteDelete(routeEntry); | 396 | router.processRouteDelete(routeEntry); |
| 395 | 397 | ||
| 396 | // Verify | 398 | // Verify |
| 397 | assertEquals(router.getRoutes().size(), 0); | 399 | assertEquals(router.getRoutes().size(), 0); |
| 398 | - assertEquals(router.getPushedRouteIntents().size(), 0); | 400 | + assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 0); |
| 399 | verify(intentService); | 401 | verify(intentService); |
| 400 | } | 402 | } |
| 401 | 403 | ||
| ... | @@ -416,14 +418,14 @@ public class RouterTest { | ... | @@ -416,14 +418,14 @@ public class RouterTest { |
| 416 | replay(intentService); | 418 | replay(intentService); |
| 417 | 419 | ||
| 418 | // Call the processRouteAdd() method in Router class | 420 | // Call the processRouteAdd() method in Router class |
| 419 | - router.leaderChanged(true); | 421 | + intentSynchronizer.leaderChanged(true); |
| 420 | - TestUtils.setField(router, "isActivatedLeader", true); | 422 | + TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); |
| 421 | router.processRouteAdd(routeEntry); | 423 | router.processRouteAdd(routeEntry); |
| 422 | 424 | ||
| 423 | // Verify | 425 | // Verify |
| 424 | assertEquals(router.getRoutes().size(), 1); | 426 | assertEquals(router.getRoutes().size(), 1); |
| 425 | assertTrue(router.getRoutes().contains(routeEntry)); | 427 | assertTrue(router.getRoutes().contains(routeEntry)); |
| 426 | - assertEquals(router.getPushedRouteIntents().size(), 0); | 428 | + assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 0); |
| 427 | verify(intentService); | 429 | verify(intentService); |
| 428 | } | 430 | } |
| 429 | } | 431 | } | ... | ... |
| ... | @@ -92,6 +92,7 @@ public class RouterTestWithAsyncArp { | ... | @@ -92,6 +92,7 @@ public class RouterTestWithAsyncArp { |
| 92 | DeviceId.deviceId("of:0000000000000003"), | 92 | DeviceId.deviceId("of:0000000000000003"), |
| 93 | PortNumber.portNumber(1)); | 93 | PortNumber.portNumber(1)); |
| 94 | 94 | ||
| 95 | + private IntentSynchronizer intentSynchronizer; | ||
| 95 | private Router router; | 96 | private Router router; |
| 96 | private InternalHostListener internalHostListener; | 97 | private InternalHostListener internalHostListener; |
| 97 | 98 | ||
| ... | @@ -114,7 +115,8 @@ public class RouterTestWithAsyncArp { | ... | @@ -114,7 +115,8 @@ public class RouterTestWithAsyncArp { |
| 114 | hostService = createMock(HostService.class); | 115 | hostService = createMock(HostService.class); |
| 115 | intentService = createMock(IntentService.class); | 116 | intentService = createMock(IntentService.class); |
| 116 | 117 | ||
| 117 | - router = new Router(APPID, intentService, | 118 | + intentSynchronizer = new IntentSynchronizer(APPID, intentService); |
| 119 | + router = new Router(APPID, intentSynchronizer, | ||
| 118 | hostService, sdnIpConfigService, interfaceService); | 120 | hostService, sdnIpConfigService, interfaceService); |
| 119 | internalHostListener = router.new InternalHostListener(); | 121 | internalHostListener = router.new InternalHostListener(); |
| 120 | } | 122 | } |
| ... | @@ -211,8 +213,8 @@ public class RouterTestWithAsyncArp { | ... | @@ -211,8 +213,8 @@ public class RouterTestWithAsyncArp { |
| 211 | replay(intentService); | 213 | replay(intentService); |
| 212 | 214 | ||
| 213 | // Call the processRouteAdd() method in Router class | 215 | // Call the processRouteAdd() method in Router class |
| 214 | - router.leaderChanged(true); | 216 | + intentSynchronizer.leaderChanged(true); |
| 215 | - TestUtils.setField(router, "isActivatedLeader", true); | 217 | + TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); |
| 216 | router.processRouteAdd(routeEntry); | 218 | router.processRouteAdd(routeEntry); |
| 217 | 219 | ||
| 218 | Host host = new DefaultHost(ProviderId.NONE, HostId.NONE, | 220 | Host host = new DefaultHost(ProviderId.NONE, HostId.NONE, |
| ... | @@ -227,9 +229,9 @@ public class RouterTestWithAsyncArp { | ... | @@ -227,9 +229,9 @@ public class RouterTestWithAsyncArp { |
| 227 | // Verify | 229 | // Verify |
| 228 | assertEquals(router.getRoutes().size(), 1); | 230 | assertEquals(router.getRoutes().size(), 1); |
| 229 | assertTrue(router.getRoutes().contains(routeEntry)); | 231 | assertTrue(router.getRoutes().contains(routeEntry)); |
| 230 | - assertEquals(router.getPushedRouteIntents().size(), 1); | 232 | + assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 1); |
| 231 | - assertEquals(router.getPushedRouteIntents().iterator().next(), | 233 | + assertEquals(intentSynchronizer.getPushedRouteIntents().iterator().next(), |
| 232 | - intent); | 234 | + intent); |
| 233 | verify(intentService); | 235 | verify(intentService); |
| 234 | verify(hostService); | 236 | verify(hostService); |
| 235 | 237 | ||
| ... | @@ -294,8 +296,8 @@ public class RouterTestWithAsyncArp { | ... | @@ -294,8 +296,8 @@ public class RouterTestWithAsyncArp { |
| 294 | replay(intentService); | 296 | replay(intentService); |
| 295 | 297 | ||
| 296 | // Call the processRouteAdd() method in Router class | 298 | // Call the processRouteAdd() method in Router class |
| 297 | - router.leaderChanged(true); | 299 | + intentSynchronizer.leaderChanged(true); |
| 298 | - TestUtils.setField(router, "isActivatedLeader", true); | 300 | + TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); |
| 299 | router.processRouteAdd(routeEntryUpdate); | 301 | router.processRouteAdd(routeEntryUpdate); |
| 300 | 302 | ||
| 301 | Host host = new DefaultHost(ProviderId.NONE, HostId.NONE, | 303 | Host host = new DefaultHost(ProviderId.NONE, HostId.NONE, |
| ... | @@ -310,8 +312,8 @@ public class RouterTestWithAsyncArp { | ... | @@ -310,8 +312,8 @@ public class RouterTestWithAsyncArp { |
| 310 | // Verify | 312 | // Verify |
| 311 | assertEquals(router.getRoutes().size(), 1); | 313 | assertEquals(router.getRoutes().size(), 1); |
| 312 | assertTrue(router.getRoutes().contains(routeEntryUpdate)); | 314 | assertTrue(router.getRoutes().contains(routeEntryUpdate)); |
| 313 | - assertEquals(router.getPushedRouteIntents().size(), 1); | 315 | + assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 1); |
| 314 | - assertEquals(router.getPushedRouteIntents().iterator().next(), | 316 | + assertEquals(intentSynchronizer.getPushedRouteIntents().iterator().next(), |
| 315 | intentNew); | 317 | intentNew); |
| 316 | verify(intentService); | 318 | verify(intentService); |
| 317 | verify(hostService); | 319 | verify(hostService); |
| ... | @@ -342,13 +344,13 @@ public class RouterTestWithAsyncArp { | ... | @@ -342,13 +344,13 @@ public class RouterTestWithAsyncArp { |
| 342 | replay(intentService); | 344 | replay(intentService); |
| 343 | 345 | ||
| 344 | // Call route deleting method in Router class | 346 | // Call route deleting method in Router class |
| 345 | - router.leaderChanged(true); | 347 | + intentSynchronizer.leaderChanged(true); |
| 346 | - TestUtils.setField(router, "isActivatedLeader", true); | 348 | + TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); |
| 347 | router.processRouteDelete(routeEntry); | 349 | router.processRouteDelete(routeEntry); |
| 348 | 350 | ||
| 349 | // Verify | 351 | // Verify |
| 350 | assertEquals(router.getRoutes().size(), 0); | 352 | assertEquals(router.getRoutes().size(), 0); |
| 351 | - assertEquals(router.getPushedRouteIntents().size(), 0); | 353 | + assertEquals(intentSynchronizer.getPushedRouteIntents().size(), 0); |
| 352 | verify(intentService); | 354 | verify(intentService); |
| 353 | } | 355 | } |
| 354 | 356 | ... | ... |
| ... | @@ -66,6 +66,7 @@ public class SdnIpTest { | ... | @@ -66,6 +66,7 @@ public class SdnIpTest { |
| 66 | private static final int MIN_PREFIX_LENGTH = 1; | 66 | private static final int MIN_PREFIX_LENGTH = 1; |
| 67 | private static final int MAX_PREFIX_LENGTH = 32; | 67 | private static final int MAX_PREFIX_LENGTH = 32; |
| 68 | 68 | ||
| 69 | + private IntentSynchronizer intentSynchronizer; | ||
| 69 | static Router router; | 70 | static Router router; |
| 70 | 71 | ||
| 71 | private SdnIpConfigService sdnIpConfigService; | 72 | private SdnIpConfigService sdnIpConfigService; |
| ... | @@ -111,7 +112,8 @@ public class SdnIpTest { | ... | @@ -111,7 +112,8 @@ public class SdnIpTest { |
| 111 | intentService = createMock(IntentService.class); | 112 | intentService = createMock(IntentService.class); |
| 112 | random = new Random(); | 113 | random = new Random(); |
| 113 | 114 | ||
| 114 | - router = new Router(APPID, intentService, hostService, | 115 | + intentSynchronizer = new IntentSynchronizer(APPID, intentService); |
| 116 | + router = new Router(APPID, intentSynchronizer, hostService, | ||
| 115 | sdnIpConfigService, interfaceService); | 117 | sdnIpConfigService, interfaceService); |
| 116 | } | 118 | } |
| 117 | 119 | ||
| ... | @@ -228,8 +230,8 @@ public class SdnIpTest { | ... | @@ -228,8 +230,8 @@ public class SdnIpTest { |
| 228 | 230 | ||
| 229 | replay(intentService); | 231 | replay(intentService); |
| 230 | 232 | ||
| 231 | - router.leaderChanged(true); | 233 | + intentSynchronizer.leaderChanged(true); |
| 232 | - TestUtils.setField(router, "isActivatedLeader", true); | 234 | + TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); |
| 233 | 235 | ||
| 234 | // Add route updates | 236 | // Add route updates |
| 235 | for (RouteUpdate update : routeUpdates) { | 237 | for (RouteUpdate update : routeUpdates) { |
| ... | @@ -239,7 +241,8 @@ public class SdnIpTest { | ... | @@ -239,7 +241,8 @@ public class SdnIpTest { |
| 239 | latch.await(5000, TimeUnit.MILLISECONDS); | 241 | latch.await(5000, TimeUnit.MILLISECONDS); |
| 240 | 242 | ||
| 241 | assertEquals(router.getRoutes().size(), numRoutes); | 243 | assertEquals(router.getRoutes().size(), numRoutes); |
| 242 | - assertEquals(router.getPushedRouteIntents().size(), numRoutes); | 244 | + assertEquals(intentSynchronizer.getPushedRouteIntents().size(), |
| 245 | + numRoutes); | ||
| 243 | 246 | ||
| 244 | verify(intentService); | 247 | verify(intentService); |
| 245 | } | 248 | } |
| ... | @@ -295,8 +298,8 @@ public class SdnIpTest { | ... | @@ -295,8 +298,8 @@ public class SdnIpTest { |
| 295 | 298 | ||
| 296 | replay(intentService); | 299 | replay(intentService); |
| 297 | 300 | ||
| 298 | - router.leaderChanged(true); | 301 | + intentSynchronizer.leaderChanged(true); |
| 299 | - TestUtils.setField(router, "isActivatedLeader", true); | 302 | + TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); |
| 300 | 303 | ||
| 301 | // Send the add updates first | 304 | // Send the add updates first |
| 302 | for (RouteUpdate update : routeUpdates) { | 305 | for (RouteUpdate update : routeUpdates) { |
| ... | @@ -314,7 +317,7 @@ public class SdnIpTest { | ... | @@ -314,7 +317,7 @@ public class SdnIpTest { |
| 314 | deleteCount.await(5000, TimeUnit.MILLISECONDS); | 317 | deleteCount.await(5000, TimeUnit.MILLISECONDS); |
| 315 | 318 | ||
| 316 | assertEquals(0, router.getRoutes().size()); | 319 | assertEquals(0, router.getRoutes().size()); |
| 317 | - assertEquals(0, router.getPushedRouteIntents().size()); | 320 | + assertEquals(0, intentSynchronizer.getPushedRouteIntents().size()); |
| 318 | verify(intentService); | 321 | verify(intentService); |
| 319 | } | 322 | } |
| 320 | 323 | ... | ... |
| ... | @@ -95,7 +95,7 @@ public class BgpSessionManagerTest { | ... | @@ -95,7 +95,7 @@ public class BgpSessionManagerTest { |
| 95 | // | 95 | // |
| 96 | bgpSessionManager = new BgpSessionManager(dummyRouteListener); | 96 | bgpSessionManager = new BgpSessionManager(dummyRouteListener); |
| 97 | // NOTE: We use port 0 to bind on any available port | 97 | // NOTE: We use port 0 to bind on any available port |
| 98 | - bgpSessionManager.startUp(0); | 98 | + bgpSessionManager.start(0); |
| 99 | 99 | ||
| 100 | // Get the port number the BGP Session Manager is listening on | 100 | // Get the port number the BGP Session Manager is listening on |
| 101 | Channel serverChannel = TestUtils.getField(bgpSessionManager, | 101 | Channel serverChannel = TestUtils.getField(bgpSessionManager, |
| ... | @@ -136,7 +136,7 @@ public class BgpSessionManagerTest { | ... | @@ -136,7 +136,7 @@ public class BgpSessionManagerTest { |
| 136 | 136 | ||
| 137 | @After | 137 | @After |
| 138 | public void tearDown() throws Exception { | 138 | public void tearDown() throws Exception { |
| 139 | - bgpSessionManager.shutDown(); | 139 | + bgpSessionManager.stop(); |
| 140 | bgpSessionManager = null; | 140 | bgpSessionManager = null; |
| 141 | } | 141 | } |
| 142 | 142 | ... | ... |
-
Please register or login to post a comment