blob: 025bbfe0135b0a376c460ca1a583294153a754a7 [file] [log] [blame]
Jonathan Hartd82f20d2013-02-21 18:04:24 -08001package net.onrc.onos.registry.controller;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -08002
Jonathan Hartbd181b62013-02-17 16:05:38 -08003import java.io.IOException;
Jonathan Hartedd6a442013-02-20 15:22:06 -08004import java.io.UnsupportedEncodingException;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -08005import java.util.ArrayList;
6import java.util.Collection;
Jonathan Hart3d7730a2013-02-22 11:51:17 -08007import java.util.Collections;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -08008import java.util.HashMap;
Jonathan Hartedd6a442013-02-20 15:22:06 -08009import java.util.List;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080010import java.util.Map;
11
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080012import net.floodlightcontroller.core.module.FloodlightModuleContext;
13import net.floodlightcontroller.core.module.FloodlightModuleException;
14import net.floodlightcontroller.core.module.IFloodlightModule;
15import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart3d7730a2013-02-22 11:51:17 -080016import net.floodlightcontroller.restserver.IRestApiService;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080017
Jonathan Hartedd6a442013-02-20 15:22:06 -080018import org.apache.zookeeper.CreateMode;
Jonathan Hartbd181b62013-02-17 16:05:38 -080019import org.apache.zookeeper.WatchedEvent;
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080020import org.apache.zookeeper.Watcher.Event.KeeperState;
Jonathan Hartbd181b62013-02-17 16:05:38 -080021import org.openflow.util.HexString;
22import org.slf4j.Logger;
23import org.slf4j.LoggerFactory;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080024
Jonathan Hartd10008d2013-02-23 17:04:08 -080025import com.google.common.base.Charsets;
Jonathan Hartbd181b62013-02-17 16:05:38 -080026import com.netflix.curator.RetryPolicy;
27import com.netflix.curator.framework.CuratorFramework;
28import com.netflix.curator.framework.CuratorFrameworkFactory;
29import com.netflix.curator.framework.api.CuratorWatcher;
Jonathan Hartedd6a442013-02-20 15:22:06 -080030import com.netflix.curator.framework.recipes.cache.ChildData;
31import com.netflix.curator.framework.recipes.cache.PathChildrenCache;
32import com.netflix.curator.framework.recipes.cache.PathChildrenCache.StartMode;
Jonathan Hart3d7730a2013-02-22 11:51:17 -080033import com.netflix.curator.framework.recipes.cache.PathChildrenCacheEvent;
34import com.netflix.curator.framework.recipes.cache.PathChildrenCacheListener;
Jonathan Hartbd181b62013-02-17 16:05:38 -080035import com.netflix.curator.framework.recipes.leader.LeaderLatch;
36import com.netflix.curator.framework.recipes.leader.Participant;
Jonathan Hart3d7730a2013-02-22 11:51:17 -080037import com.netflix.curator.retry.ExponentialBackoffRetry;
Jonathan Hartbd181b62013-02-17 16:05:38 -080038
Jonathan Hart7bf62172013-02-28 13:17:18 -080039/**
40 * A registry service that uses Zookeeper. All data is stored in Zookeeper,
41 * so this can be used as a global registry in a multi-node ONOS cluster.
42 * @author jono
43 *
44 */
Jonathan Hartbd766972013-02-22 15:13:03 -080045public class ZookeeperRegistry implements IFloodlightModule, IControllerRegistryService {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080046
Jonathan Hartbd766972013-02-22 15:13:03 -080047 protected static Logger log = LoggerFactory.getLogger(ZookeeperRegistry.class);
48 protected String controllerId = null;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080049
Jonathan Hart3d7730a2013-02-22 11:51:17 -080050 protected IRestApiService restApi;
51
Jonathan Hart7bf62172013-02-28 13:17:18 -080052 //This is the default, it's overwritten by the connectionString configuration parameter
Jonathan Hartbd181b62013-02-17 16:05:38 -080053 protected String connectionString = "localhost:2181";
Jonathan Hart3d7730a2013-02-22 11:51:17 -080054
Jonathan Hartbd181b62013-02-17 16:05:38 -080055 private final String namespace = "onos";
Jonathan Hartedd6a442013-02-20 15:22:06 -080056 private final String switchLatchesPath = "/switches";
Jonathan Hart3d7730a2013-02-22 11:51:17 -080057 private final String controllerPath = "/controllers";
Jonathan Hartbd181b62013-02-17 16:05:38 -080058
59 protected CuratorFramework client;
Jonathan Hartedd6a442013-02-20 15:22:06 -080060
Jonathan Hartedd6a442013-02-20 15:22:06 -080061 protected PathChildrenCache controllerCache;
Jonathan Hart3d7730a2013-02-22 11:51:17 -080062 protected PathChildrenCache switchCache;
Jonathan Hartbd181b62013-02-17 16:05:38 -080063
64 protected Map<String, LeaderLatch> switchLatches;
Jonathan Hartd82f20d2013-02-21 18:04:24 -080065 protected Map<String, ControlChangeCallback> switchCallbacks;
Jonathan Hart3d7730a2013-02-22 11:51:17 -080066 protected Map<String, PathChildrenCache> switchPathCaches;
Jonathan Hartbd181b62013-02-17 16:05:38 -080067
Jonathan Hart97801ac2013-02-26 14:29:16 -080068 //Zookeeper performance-related configuration
Jonathan Hartcc957a02013-02-26 10:39:04 -080069 protected static final int sessionTimeout = 2000;
70 protected static final int connectionTimeout = 4000;
Jonathan Hart57080fb2013-02-21 10:55:46 -080071
Jonathan Hart7bf62172013-02-28 13:17:18 -080072 /**
73 * Watches for changes in switch leadership election. The Curator
74 * LeaderLatch doesn't notify us when leadership changes so we set a watch
75 * on the election znodes to get leadership change events. The process
76 * method will be called whenever the switches children change in
77 * Zookeeper. We then have to work out whether to send a control-changed
78 * event to our clients and reset the watch.
79 *
80 * TODO I think it's possible to miss events that happen while we're
81 * processing the watch and before we've set a new watch. Need to think
82 * of a safer way to implement leader change notifications.
83 *
84 */
Jonathan Hartbd181b62013-02-17 16:05:38 -080085 protected class ParamaterizedCuratorWatcher implements CuratorWatcher {
86 private String dpid;
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080087 private boolean isLeader = false;
Jonathan Hartbd181b62013-02-17 16:05:38 -080088 private String latchPath;
89
90 public ParamaterizedCuratorWatcher(String dpid, String latchPath){
91 this.dpid = dpid;
92 this.latchPath = latchPath;
93 }
94
95 @Override
Jonathan Hartedd6a442013-02-20 15:22:06 -080096 public synchronized void process(WatchedEvent event) throws Exception {
Jonathan Hartbd181b62013-02-17 16:05:38 -080097 log.debug("Watch Event: {}", event);
98
Jonathan Hartbd181b62013-02-17 16:05:38 -080099
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800100 if (event.getState() == KeeperState.Disconnected){
101 if (isLeader) {
102 log.debug("Disconnected while leader - lost leadership for {}", dpid);
103
104 isLeader = false;
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800105 ControlChangeCallback cb = switchCallbacks.get(dpid);
106 if (cb != null) {
107 //Allow callback to be null if the requester doesn't want a callback
108 cb.controlChanged(HexString.toLong(dpid), false);
109 }
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800110 }
111 return;
Jonathan Hart7bf62172013-02-28 13:17:18 -0800112 //TODO Watcher is never reset once we reconnect to Zookeeper
113 }
114
115 LeaderLatch latch = switchLatches.get(dpid);
116 if (latch == null){
117 log.debug("In watcher process, looks like control was released for {}",
118 dpid);
119 return;
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800120 }
Jonathan Hartbd181b62013-02-17 16:05:38 -0800121
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800122 try {
Jonathan Hartedd6a442013-02-20 15:22:06 -0800123
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800124 Participant leader = latch.getLeader();
125
Jonathan Hartbd766972013-02-22 15:13:03 -0800126 if (leader.getId().equals(controllerId) && !isLeader){
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800127 log.debug("Became leader for {}", dpid);
128
129 isLeader = true;
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800130 switchCallbacks.get(dpid).controlChanged(HexString.toLong(dpid), true);
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800131 }
Jonathan Hartbd766972013-02-22 15:13:03 -0800132 else if (!leader.getId().equals(controllerId) && isLeader){
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800133 log.debug("Lost leadership for {}", dpid);
134
135 isLeader = false;
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800136 switchCallbacks.get(dpid).controlChanged(HexString.toLong(dpid), false);
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800137 }
138 } catch (Exception e){
139 if (isLeader){
Jonathan Hart7bf62172013-02-28 13:17:18 -0800140 log.debug("Exception checking leadership status. Assume leadership lost for {}",
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800141 dpid);
142
143 isLeader = false;
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800144 switchCallbacks.get(dpid).controlChanged(HexString.toLong(dpid), false);
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800145 }
Jonathan Hart7bf62172013-02-28 13:17:18 -0800146 } finally {
147 client.getChildren().usingWatcher(this).inBackground().forPath(latchPath);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800148 }
Jonathan Hartbd181b62013-02-17 16:05:38 -0800149 //client.getChildren().usingWatcher(this).forPath(latchPath);
150 }
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800151 }
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800152
153
Jonathan Hart7bf62172013-02-28 13:17:18 -0800154 /**
155 * Listens for changes to the switch znodes in Zookeeper. This maintains
156 * the second level of PathChildrenCaches that hold the controllers
157 * contending for each switch - there's one for each switch.
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800158 */
159 PathChildrenCacheListener switchPathCacheListener = new PathChildrenCacheListener() {
160 @Override
161 public void childEvent(CuratorFramework client,
162 PathChildrenCacheEvent event) throws Exception {
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800163 log.debug("Root switch path cache got {} event", event.getType());
164
165 String strSwitch = null;
166 if (event.getData() != null){
167 log.debug("Event path {}", event.getData().getPath());
168 String[] splitted = event.getData().getPath().split("/");
169 strSwitch = splitted[splitted.length - 1];
170 log.debug("Switch name is {}", strSwitch);
171 }
172
173 switch (event.getType()){
174 case CHILD_ADDED:
175 case CHILD_UPDATED:
176 //Check we have a PathChildrenCache for this child, add one if not
177 if (switchPathCaches.get(strSwitch) == null){
178 PathChildrenCache pc = new PathChildrenCache(client,
179 event.getData().getPath(), true);
180 pc.start(StartMode.NORMAL);
181 switchPathCaches.put(strSwitch, pc);
182 }
183 break;
184 case CHILD_REMOVED:
185 //Remove our PathChildrenCache for this child
186 PathChildrenCache pc = switchPathCaches.remove(strSwitch);
187 pc.close();
188 break;
189 default:
190 //All other events are connection status events. We need to do anything
191 //as the path cache handles these on its own.
192 break;
193 }
194
195 }
196 };
Jonathan Hartedd6a442013-02-20 15:22:06 -0800197
Jonathan Hartbd181b62013-02-17 16:05:38 -0800198
199 @Override
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800200 public void requestControl(long dpid, ControlChangeCallback cb) throws RegistryException {
Jonathan Hart7bf62172013-02-28 13:17:18 -0800201 log.info("Requesting control for {}", HexString.toHexString(dpid));
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800202
Jonathan Hartbd766972013-02-22 15:13:03 -0800203 if (controllerId == null){
204 throw new RuntimeException("Must register a controller before calling requestControl");
Jonathan Hartbd181b62013-02-17 16:05:38 -0800205 }
206
207 String dpidStr = HexString.toHexString(dpid);
208 String latchPath = switchLatchesPath + "/" + dpidStr;
209
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800210 if (switchLatches.get(dpidStr) != null){
Jonathan Hart3c0eccd2013-03-12 22:32:50 -0700211 //throw new RuntimeException("Leader election for switch " + dpidStr +
212 // "is already running");
213 log.debug("Already contesting {}, returning", HexString.toHexString(dpid));
214 return;
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800215 }
216
Jonathan Hartbd766972013-02-22 15:13:03 -0800217 LeaderLatch latch = new LeaderLatch(client, latchPath, controllerId);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800218 switchLatches.put(dpidStr, latch);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800219 switchCallbacks.put(dpidStr, cb);
220
221 try {
222 //client.getChildren().usingWatcher(watcher).inBackground().forPath(singleLatchPath);
223 client.getChildren().usingWatcher(
224 new ParamaterizedCuratorWatcher(dpidStr, latchPath))
225 .inBackground().forPath(latchPath);
226 latch.start();
227 } catch (Exception e) {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800228 log.warn("Error starting leader latch: {}", e.getMessage());
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800229 throw new RegistryException("Error starting leader latch for " + dpidStr, e);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800230 }
231
232 }
233
234 @Override
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800235 public void releaseControl(long dpid) {
Jonathan Hart7bf62172013-02-28 13:17:18 -0800236 log.info("Releasing control for {}", HexString.toHexString(dpid));
Jonathan Hart57080fb2013-02-21 10:55:46 -0800237
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800238 String dpidStr = HexString.toHexString(dpid);
239
240 LeaderLatch latch = switchLatches.get(dpidStr);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800241 if (latch == null) {
Jonathan Hart7bf62172013-02-28 13:17:18 -0800242 log.debug("Trying to release control of a switch we are not contesting");
Jonathan Hartbd181b62013-02-17 16:05:38 -0800243 return;
244 }
245
246 try {
247 latch.close();
248 } catch (IOException e) {
Jonathan Hart7bf62172013-02-28 13:17:18 -0800249 //I think it's OK not to do anything here. Either the node got
250 //deleted correctly, or the connection went down and the node got deleted.
Jonathan Hart1be46262013-02-20 16:43:51 -0800251 } finally {
252 switchLatches.remove(dpidStr);
253 switchCallbacks.remove(dpidStr);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800254 }
255 }
256
257 @Override
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800258 public boolean hasControl(long dpid) {
Jonathan Hart57080fb2013-02-21 10:55:46 -0800259
Jonathan Hartbd181b62013-02-17 16:05:38 -0800260 LeaderLatch latch = switchLatches.get(HexString.toHexString(dpid));
261
262 if (latch == null) {
263 log.warn("No leader latch for dpid {}", HexString.toHexString(dpid));
264 return false;
265 }
266
Jonathan Hartbd181b62013-02-17 16:05:38 -0800267 try {
Jonathan Hartbd766972013-02-22 15:13:03 -0800268 return latch.getLeader().getId().equals(controllerId);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800269 } catch (Exception e) {
270 //TODO swallow exception?
271 return false;
272 }
273 }
274
275 @Override
Jonathan Hart7bf62172013-02-28 13:17:18 -0800276 public String getControllerId() {
Jonathan Hartbd766972013-02-22 15:13:03 -0800277 return controllerId;
Jonathan Hartbd181b62013-02-17 16:05:38 -0800278 }
279
Jonathan Hartedd6a442013-02-20 15:22:06 -0800280 @Override
Jonathan Hart57080fb2013-02-21 10:55:46 -0800281 public Collection<String> getAllControllers() throws RegistryException {
Jonathan Hartedd6a442013-02-20 15:22:06 -0800282 log.debug("Getting all controllers");
Jonathan Hart1be46262013-02-20 16:43:51 -0800283
Jonathan Hartedd6a442013-02-20 15:22:06 -0800284 List<String> controllers = new ArrayList<String>();
285 for (ChildData data : controllerCache.getCurrentData()){
286
287 String d = null;
288 try {
289 d = new String(data.getData(), "UTF-8");
290 } catch (UnsupportedEncodingException e) {
Jonathan Hart57080fb2013-02-21 10:55:46 -0800291 throw new RegistryException("Error encoding string", e);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800292 }
293
294 controllers.add(d);
295 }
296 return controllers;
297 }
298
299 @Override
Jonathan Hart57080fb2013-02-21 10:55:46 -0800300 public void registerController(String id) throws RegistryException {
Jonathan Hartd10008d2013-02-23 17:04:08 -0800301 if (controllerId != null) {
302 throw new RegistryException(
303 "Controller already registered with id " + controllerId);
304 }
Jonathan Hartbd766972013-02-22 15:13:03 -0800305
306 controllerId = id;
Jonathan Hart57080fb2013-02-21 10:55:46 -0800307
Jonathan Hartd10008d2013-02-23 17:04:08 -0800308 byte bytes[] = id.getBytes(Charsets.UTF_8);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800309
310 String path = controllerPath + "/" + id;
311
312 log.info("Registering controller with id {}", id);
313
Jonathan Hart57080fb2013-02-21 10:55:46 -0800314 //Create ephemeral node in controller registry
Jonathan Hartedd6a442013-02-20 15:22:06 -0800315 try {
316 client.create().withProtection().withMode(CreateMode.EPHEMERAL)
317 .forPath(path, bytes);
318 } catch (Exception e) {
Jonathan Hart57080fb2013-02-21 10:55:46 -0800319 throw new RegistryException("Error contacting the Zookeeper service", e);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800320 }
321 }
322
323 @Override
Jonathan Hart57080fb2013-02-21 10:55:46 -0800324 public String getControllerForSwitch(long dpid) throws RegistryException {
Jonathan Hartedd6a442013-02-20 15:22:06 -0800325 // TODO Work out how we should store this controller/switch data.
326 // The leader latch might be a index to the /controllers collections
327 // which holds more info on the controller (how to talk to it for example).
328
Jonathan Hartedd6a442013-02-20 15:22:06 -0800329 String strDpid = HexString.toHexString(dpid);
330 LeaderLatch latch = switchLatches.get(strDpid);
331
332 if (latch == null){
333 log.warn("Tried to get controller for non-existent switch");
334 return null;
335 }
336
337 Participant leader = null;
338 try {
339 leader = latch.getLeader();
340 } catch (Exception e) {
Jonathan Hart57080fb2013-02-21 10:55:46 -0800341 throw new RegistryException("Error contacting the Zookeeper service", e);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800342 }
343
344 return leader.getId();
345 }
346
347 @Override
348 public Collection<Long> getSwitchesControlledByController(String controllerId) {
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800349 //TODO remove this if not needed
Jonathan Hartbd766972013-02-22 15:13:03 -0800350 throw new RuntimeException("Not yet implemented");
Jonathan Hartedd6a442013-02-20 15:22:06 -0800351 }
Jonathan Hartbd181b62013-02-17 16:05:38 -0800352
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800353
354 @Override
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800355 public Map<String, List<ControllerRegistryEntry>> getAllSwitches() {
356 Map<String, List<ControllerRegistryEntry>> data =
357 new HashMap<String, List<ControllerRegistryEntry>>();
358
359 for (Map.Entry<String, PathChildrenCache> entry : switchPathCaches.entrySet()){
360 List<ControllerRegistryEntry> contendingControllers =
361 new ArrayList<ControllerRegistryEntry>();
362
363 if (entry.getValue().getCurrentData().size() < 1){
364 log.info("Switch entry with no leader elections: {}", entry.getKey());
365 continue;
366 }
367
368 for (ChildData d : entry.getValue().getCurrentData()) {
Jonathan Hart97801ac2013-02-26 14:29:16 -0800369
Jonathan Hartd10008d2013-02-23 17:04:08 -0800370 String controllerId = new String(d.getData(), Charsets.UTF_8);
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800371
372 String[] splitted = d.getPath().split("-");
373 int sequenceNumber = Integer.parseInt(splitted[splitted.length - 1]);
374
375 contendingControllers.add(new ControllerRegistryEntry(controllerId, sequenceNumber));
376 }
377
378 Collections.sort(contendingControllers);
379 data.put(entry.getKey(), contendingControllers);
380 }
381 return data;
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800382 }
383
Jonathan Hartbd181b62013-02-17 16:05:38 -0800384 /*
385 * IFloodlightModule
386 */
387
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800388 @Override
389 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hartedd6a442013-02-20 15:22:06 -0800390 Collection<Class<? extends IFloodlightService>> l =
391 new ArrayList<Class<? extends IFloodlightService>>();
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800392 l.add(IControllerRegistryService.class);
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800393 return l;
394 }
395
396 @Override
397 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
398 Map<Class<? extends IFloodlightService>, IFloodlightService> m =
399 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800400 m.put(IControllerRegistryService.class, this);
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800401 return m;
402 }
403
404 @Override
405 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800406 Collection<Class<? extends IFloodlightService>> l =
407 new ArrayList<Class<? extends IFloodlightService>>();
408 l.add(IRestApiService.class);
409 return l;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800410 }
411
412 @Override
413 public void init (FloodlightModuleContext context) throws FloodlightModuleException {
Jonathan Hartbd766972013-02-22 15:13:03 -0800414 log.info("Initialising the Zookeeper Registry - Zookeeper connection required");
415
Jonathan Hart97801ac2013-02-26 14:29:16 -0800416 //Read the Zookeeper connection string from the config
417 Map<String, String> configParams = context.getConfigParams(this);
418 String connectionString = configParams.get("connectionString");
419 if (connectionString != null){
420 this.connectionString = connectionString;
Jonathan Hart57080fb2013-02-21 10:55:46 -0800421 }
Jonathan Hart97801ac2013-02-26 14:29:16 -0800422 log.info("Setting Zookeeper connection string to {}", this.connectionString);
Jonathan Hart57080fb2013-02-21 10:55:46 -0800423
Jonathan Hart97801ac2013-02-26 14:29:16 -0800424 restApi = context.getServiceImpl(IRestApiService.class);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800425
426 switchLatches = new HashMap<String, LeaderLatch>();
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800427 switchCallbacks = new HashMap<String, ControlChangeCallback>();
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800428 switchPathCaches = new HashMap<String, PathChildrenCache>();
Jonathan Hartbd181b62013-02-17 16:05:38 -0800429
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800430 RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
Jonathan Hart97801ac2013-02-26 14:29:16 -0800431 client = CuratorFrameworkFactory.newClient(this.connectionString,
Jonathan Hartcc957a02013-02-26 10:39:04 -0800432 sessionTimeout, connectionTimeout, retryPolicy);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800433
434 client.start();
435
436 client = client.usingNamespace(namespace);
Jonathan Hart97801ac2013-02-26 14:29:16 -0800437
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800438
Jonathan Hartedd6a442013-02-20 15:22:06 -0800439 controllerCache = new PathChildrenCache(client, controllerPath, true);
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800440 switchCache = new PathChildrenCache(client, switchLatchesPath, true);
441 switchCache.getListenable().addListener(switchPathCacheListener);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800442
443 try {
444 controllerCache.start(StartMode.BUILD_INITIAL_CACHE);
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800445
446 //Don't prime the cache, we want a notification for each child node in the path
447 switchCache.start(StartMode.NORMAL);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800448 } catch (Exception e) {
Jonathan Hart7bf62172013-02-28 13:17:18 -0800449 throw new FloodlightModuleException("Error initialising ZookeeperRegistry: "
450 + e.getMessage());
Jonathan Hartedd6a442013-02-20 15:22:06 -0800451 }
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800452 }
453
454 @Override
455 public void startUp (FloodlightModuleContext context) {
Jonathan Hart3d7730a2013-02-22 11:51:17 -0800456 restApi.addRestletRoutable(new RegistryWebRoutable());
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800457 }
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800458}