Pavlin Radoslavov

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
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,42 +146,8 @@ public class Router implements RouteListener { ...@@ -177,42 +146,8 @@ 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 } 149 }
196 } 150 }
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 - }
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 - }
216 151
217 @Override 152 @Override
218 public void update(RouteUpdate routeUpdate) { 153 public void update(RouteUpdate routeUpdate) {
...@@ -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,8 +229,8 @@ public class RouterTestWithAsyncArp { ...@@ -227,8 +229,8 @@ 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);
...@@ -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
......