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
630 additions
and
316 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,6 +93,7 @@ public class IntentSynchronizer { | ... | @@ -88,6 +93,7 @@ public class IntentSynchronizer { |
88 | * Stops the synchronizer. | 93 | * Stops the synchronizer. |
89 | */ | 94 | */ |
90 | public void stop() { | 95 | public void stop() { |
96 | + synchronized (this) { | ||
91 | // Stop the thread(s) | 97 | // Stop the thread(s) |
92 | bgpIntentsSynchronizerExecutor.shutdownNow(); | 98 | bgpIntentsSynchronizerExecutor.shutdownNow(); |
93 | 99 | ||
... | @@ -97,19 +103,37 @@ public class IntentSynchronizer { | ... | @@ -97,19 +103,37 @@ public class IntentSynchronizer { |
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 | } | 105 | } |
100 | - log.debug("Withdrawing all SDN-IP Route Intents..."); | 106 | + |
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(); | ||
101 | for (Intent intent : intentService.getIntents()) { | 113 | for (Intent intent : intentService.getIntents()) { |
102 | - if (!(intent instanceof MultiPointToSinglePointIntent) | 114 | + // Skip the intents from other applications |
103 | - || !intent.appId().equals(appId)) { | 115 | + if (!intent.appId().equals(appId)) { |
104 | continue; | 116 | continue; |
105 | } | 117 | } |
106 | - intentService.withdraw(intent); | 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()); | ||
107 | } | 128 | } |
129 | + intentService.execute(builder.build()); | ||
130 | + leaderChanged(false); | ||
108 | 131 | ||
109 | - pushedRouteIntents.clear(); | 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 | /** |
... | @@ -162,7 +186,7 @@ public class IntentSynchronizer { | ... | @@ -162,7 +186,7 @@ public class IntentSynchronizer { |
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,32 +270,56 @@ public class IntentSynchronizer { | ... | @@ -216,32 +270,56 @@ 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 | } |
303 | + fetchedIntents.put(new IntentKey(intent), intent); | ||
304 | + } | ||
305 | + | ||
306 | + computeIntentsDelta(localIntents, fetchedIntents, | ||
307 | + storeInMemoryIntents, addIntents, | ||
308 | + deleteIntents); | ||
309 | + | ||
310 | + // | ||
311 | + // Perform the actions: | ||
312 | + // 1. Store in memory fetched intents that are same. Can be done | ||
313 | + // even if we are not the leader anymore | ||
314 | + // 2. Delete intents: check if the leader before the operation | ||
315 | + // 3. Add intents: check if the leader before the operation | ||
316 | + // | ||
317 | + for (Intent intent : storeInMemoryIntents) { | ||
318 | + // Store the intent in memory based on its type | ||
319 | + if (intent instanceof MultiPointToSinglePointIntent) { | ||
242 | MultiPointToSinglePointIntent mp2pIntent = | 320 | MultiPointToSinglePointIntent mp2pIntent = |
243 | (MultiPointToSinglePointIntent) intent; | 321 | (MultiPointToSinglePointIntent) intent; |
244 | - | 322 | + // Find the IP prefix |
245 | Criterion c = | 323 | Criterion c = |
246 | mp2pIntent.selector().getCriterion(Criterion.Type.IPV4_DST); | 324 | mp2pIntent.selector().getCriterion(Criterion.Type.IPV4_DST); |
247 | if (c != null && c instanceof IPCriterion) { | 325 | if (c != null && c instanceof IPCriterion) { |
... | @@ -251,156 +329,253 @@ public class IntentSynchronizer { | ... | @@ -251,156 +329,253 @@ public class IntentSynchronizer { |
251 | // TODO: For now we support only IPv4 | 329 | // TODO: For now we support only IPv4 |
252 | continue; | 330 | continue; |
253 | } | 331 | } |
254 | - fetchedIntents.put(ip4Prefix, mp2pIntent); | 332 | + log.debug("Intent synchronization: updating " + |
333 | + "in-memory Route Intent for prefix {}", | ||
334 | + ip4Prefix); | ||
335 | + routeIntents.put(ip4Prefix, mp2pIntent); | ||
255 | } else { | 336 | } else { |
256 | - log.warn("No IPV4_DST criterion found for intent {}", | 337 | + log.warn("No IPV4_DST criterion found for Intent {}", |
257 | mp2pIntent.id()); | 338 | mp2pIntent.id()); |
258 | } | 339 | } |
340 | + continue; | ||
341 | + } | ||
342 | + if (intent instanceof PointToPointIntent) { | ||
343 | + PointToPointIntent p2pIntent = (PointToPointIntent) intent; | ||
344 | + log.debug("Intent synchronization: updating " + | ||
345 | + "in-memory Peer Intent {}", p2pIntent); | ||
346 | + peerIntents.put(new IntentKey(intent), p2pIntent); | ||
347 | + continue; | ||
348 | + } | ||
349 | + } | ||
259 | 350 | ||
351 | + // Withdraw Intents | ||
352 | + IntentOperations.Builder builder = IntentOperations.builder(); | ||
353 | + for (Intent intent : deleteIntents) { | ||
354 | + builder.addWithdrawOperation(intent.id()); | ||
355 | + log.debug("Intent synchronization: deleting Intent {}", | ||
356 | + intent); | ||
260 | } | 357 | } |
358 | + if (!isElectedLeader) { | ||
359 | + isActivatedLeader = false; | ||
360 | + return; | ||
361 | + } | ||
362 | + intentService.execute(builder.build()); | ||
363 | + | ||
364 | + // Add Intents | ||
365 | + builder = IntentOperations.builder(); | ||
366 | + for (Intent intent : addIntents) { | ||
367 | + builder.addSubmitOperation(intent); | ||
368 | + log.debug("Intent synchronization: adding Intent {}", intent); | ||
369 | + } | ||
370 | + if (!isElectedLeader) { | ||
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; | ||
380 | + } | ||
381 | + log.debug("Syncing SDN-IP routes completed."); | ||
382 | + } | ||
383 | + } | ||
384 | + | ||
385 | + /** | ||
386 | + * Computes the delta in two sets of Intents: local in-memory Intents, | ||
387 | + * and intents fetched from the Intent framework. | ||
388 | + * | ||
389 | + * @param localIntents the local in-memory Intents | ||
390 | + * @param fetchedIntents the Intents fetched from the Intent framework | ||
391 | + * @param storeInMemoryIntents the Intents that should be stored in memory. | ||
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. | ||
400 | + */ | ||
401 | + private void computeIntentsDelta( | ||
402 | + final Map<IntentKey, Intent> localIntents, | ||
403 | + final Map<IntentKey, Intent> fetchedIntents, | ||
404 | + Collection<Intent> storeInMemoryIntents, | ||
405 | + Collection<Intent> addIntents, | ||
406 | + Collection<Intent> deleteIntents) { | ||
261 | 407 | ||
262 | // | 408 | // |
263 | - // Compare for each prefix the local IN-MEMORY Intents with the | 409 | + // Compute the deltas between the LOCAL in-memory Intents and the |
264 | // FETCHED Intents: | 410 | // FETCHED Intents: |
265 | - // - If the IN-MEMORY Intent is same as the FETCHED Intent, store | 411 | + // - If an Intent is in both the LOCAL and FETCHED sets: |
266 | - // the FETCHED Intent in the local memory (i.e., override the | 412 | + // If the FETCHED Intent is WITHDRAWING or WITHDRAWN, then |
267 | - // IN-MEMORY Intent) to preserve the original Intent ID | 413 | + // the LOCAL Intent should be added/installed; otherwise the |
268 | - // - if the IN-MEMORY Intent is not same as the FETCHED Intent, | 414 | + // FETCHED intent should be stored in the local memory |
269 | - // delete the FETCHED Intent, and push/install the IN-MEMORY | 415 | + // (i.e., override the LOCAL Intent) to preserve the original |
270 | - // Intent. | 416 | + // Intent ID. |
271 | - // - If there is an IN-MEMORY Intent for a prefix, but no FETCHED | 417 | + // - if a LOCAL Intent is not in the FETCHED set, then the LOCAL |
272 | - // Intent for same prefix, then push/install the IN-MEMORY | 418 | + // Intent should be added/installed. |
273 | - // Intent. | 419 | + // - If a FETCHED Intent is not in the LOCAL set, then the FETCHED |
274 | - // - If there is a FETCHED Intent for a prefix, but no IN-MEMORY | 420 | + // Intent should be deleted/withdrawn. |
275 | - // Intent for same prefix, then delete/withdraw the FETCHED | ||
276 | - // Intent. | ||
277 | // | 421 | // |
278 | - Collection<Pair<Ip4Prefix, MultiPointToSinglePointIntent>> | 422 | + for (Map.Entry<IntentKey, Intent> entry : localIntents.entrySet()) { |
279 | - storeInMemoryIntents = new LinkedList<>(); | 423 | + IntentKey intentKey = entry.getKey(); |
280 | - Collection<Pair<Ip4Prefix, MultiPointToSinglePointIntent>> | 424 | + Intent localIntent = entry.getValue(); |
281 | - addIntents = new LinkedList<>(); | 425 | + Intent fetchedIntent = fetchedIntents.get(intentKey); |
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 | 426 | ||
292 | if (fetchedIntent == null) { | 427 | if (fetchedIntent == null) { |
293 | // | 428 | // |
294 | - // No FETCHED Intent for same prefix: push the IN-MEMORY | 429 | + // No FETCHED Intent found: push the LOCAL Intent. |
295 | - // Intent. | ||
296 | // | 430 | // |
297 | - addIntents.add(Pair.of(prefix, inMemoryIntent)); | 431 | + addIntents.add(localIntent); |
298 | continue; | 432 | continue; |
299 | } | 433 | } |
300 | 434 | ||
301 | - IntentState state = intentService.getIntentState(fetchedIntent.id()); | 435 | + IntentState state = |
436 | + intentService.getIntentState(fetchedIntent.id()); | ||
302 | if (state == IntentState.WITHDRAWING || | 437 | if (state == IntentState.WITHDRAWING || |
303 | state == IntentState.WITHDRAWN) { | 438 | state == IntentState.WITHDRAWN) { |
304 | // The intent has been withdrawn but according to our route | 439 | // The intent has been withdrawn but according to our route |
305 | // table it should be installed. We'll reinstall it. | 440 | // table it should be installed. We'll reinstall it. |
306 | - addIntents.add(Pair.of(prefix, inMemoryIntent)); | 441 | + addIntents.add(localIntent); |
307 | - } | 442 | + continue; |
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 | } | 443 | } |
325 | - fetchedIntents.remove(prefix); | 444 | + storeInMemoryIntents.add(fetchedIntent); |
326 | } | 445 | } |
327 | 446 | ||
328 | - // | 447 | + for (Map.Entry<IntentKey, Intent> entry : fetchedIntents.entrySet()) { |
329 | - // Any remaining FETCHED Intents have to be deleted/withdrawn | 448 | + IntentKey intentKey = entry.getKey(); |
330 | - // | 449 | + Intent fetchedIntent = entry.getValue(); |
331 | - for (Map.Entry<Ip4Prefix, MultiPointToSinglePointIntent> entry : | 450 | + Intent localIntent = localIntents.get(intentKey); |
332 | - fetchedIntents.entrySet()) { | 451 | + |
333 | - Ip4Prefix prefix = entry.getKey(); | 452 | + if (localIntent != null) { |
334 | - MultiPointToSinglePointIntent fetchedIntent = entry.getValue(); | 453 | + continue; |
335 | - deleteIntents.add(Pair.of(prefix, fetchedIntent)); | ||
336 | } | 454 | } |
337 | 455 | ||
338 | - // | 456 | + IntentState state = |
339 | - // Perform the actions: | 457 | + intentService.getIntentState(fetchedIntent.id()); |
340 | - // 1. Store in memory fetched intents that are same. Can be done | 458 | + if (state == IntentState.WITHDRAWING || |
341 | - // even if we are not the leader anymore | 459 | + state == IntentState.WITHDRAWN) { |
342 | - // 2. Delete intents: check if the leader before each operation | 460 | + // Nothing to do. The intent has been already withdrawn. |
343 | - // 3. Add intents: check if the leader before each operation | 461 | + continue; |
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 | } | 462 | } |
353 | // | 463 | // |
354 | - isActivatedLeader = true; // Allow push of Intents | 464 | + // No LOCAL Intent found: delete/withdraw the FETCHED Intent. |
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 | // | 465 | // |
368 | - for (Pair<Ip4Prefix, MultiPointToSinglePointIntent> pair : | 466 | + deleteIntents.add(fetchedIntent); |
369 | - addIntents) { | ||
370 | - Ip4Prefix prefix = pair.getLeft(); | ||
371 | - MultiPointToSinglePointIntent intent = pair.getRight(); | ||
372 | - if (!isElectedLeader) { | ||
373 | - isActivatedLeader = false; | ||
374 | - return; | ||
375 | } | 467 | } |
376 | - log.debug("Intent synchronization: adding Intent for " + | ||
377 | - "prefix: {}", prefix); | ||
378 | - intentService.submit(intent); | ||
379 | } | 468 | } |
380 | - if (!isElectedLeader) { | 469 | + |
381 | - isActivatedLeader = false; | 470 | + /** |
382 | - } | 471 | + * Helper class that can be used to compute the key for an Intent by |
383 | - log.debug("Syncing SDN-IP routes completed."); | 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; | ||
384 | } | 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()); | ||
385 | } | 505 | } |
386 | 506 | ||
387 | /** | 507 | /** |
388 | - * Compares two Multi-point to Single Point Intents whether they represent | 508 | + * Compares two Point-to-Point Intents whether they represent |
389 | * same logical intention. | 509 | * same logical intention. |
390 | * | 510 | * |
391 | * @param intent1 the first Intent to compare | 511 | * @param intent1 the first Intent to compare |
392 | * @param intent2 the second Intent to compare | 512 | * @param intent2 the second Intent to compare |
393 | - * @return true if both Intents represent same logical intention, otherwise | 513 | + * @return true if both Intents represent same logical intention, |
394 | - * false | 514 | + * otherwise false |
395 | */ | 515 | */ |
396 | - private boolean compareMultiPointToSinglePointIntents( | 516 | + static boolean equalIntents(PointToPointIntent intent1, |
397 | - MultiPointToSinglePointIntent intent1, | 517 | + PointToPointIntent intent2) { |
398 | - MultiPointToSinglePointIntent 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 | + } | ||
399 | 524 | ||
400 | - return Objects.equal(intent1.appId(), intent2.appId()) && | 525 | + @Override |
401 | - Objects.equal(intent1.selector(), intent2.selector()) && | 526 | + public int hashCode() { |
402 | - Objects.equal(intent1.treatment(), intent2.treatment()) && | 527 | + if (intent instanceof PointToPointIntent) { |
403 | - Objects.equal(intent1.ingressPoints(), intent2.ingressPoints()) && | 528 | + PointToPointIntent p2pIntent = (PointToPointIntent) intent; |
404 | - Objects.equal(intent1.egressPoint(), intent2.egressPoint()); | 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 | - | ||
187 | - // | ||
188 | - // Keep periodically extending the lock expiration. | ||
189 | - // If there are multiple back-to-back failures to extend (with | ||
190 | - // extra sleep time between retrials), then release the lock. | ||
191 | - // | ||
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); | 183 | intentSynchronizer.leaderChanged(false); |
210 | - leaderLock.unlock(); | 184 | + break; |
211 | - break; // Try again to get the lock | 185 | + case LEADER_REELECTED: |
212 | - } | 186 | + break; |
213 | - } | 187 | + default: |
188 | + break; | ||
214 | } | 189 | } |
215 | - } catch (InterruptedException e) { | ||
216 | - // Thread interrupted. Time to shutdown | ||
217 | - log.debug("SDN-IP Leader Interrupted"); | ||
218 | } | 190 | } |
219 | } | 191 | } |
220 | - // If we reach here, the instance was shutdown | ||
221 | - intentSynchronizer.leaderChanged(false); | ||
222 | - leaderLock.unlock(); | ||
223 | - } | ||
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