blob: 84f17c3ae6cc12a7148a4f8326fba08f1d0517f4 [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;
Jonathan Hartbd181b62013-02-17 16:05:38 -08005import java.net.UnknownHostException;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -08006import java.util.ArrayList;
7import java.util.Collection;
8import 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;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080016
Jonathan Hartedd6a442013-02-20 15:22:06 -080017import org.apache.zookeeper.CreateMode;
Jonathan Hartbd181b62013-02-17 16:05:38 -080018import org.apache.zookeeper.WatchedEvent;
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080019import org.apache.zookeeper.Watcher.Event.KeeperState;
Jonathan Hartbd181b62013-02-17 16:05:38 -080020import org.openflow.util.HexString;
21import org.slf4j.Logger;
22import org.slf4j.LoggerFactory;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080023
Jonathan Hartbd181b62013-02-17 16:05:38 -080024import com.netflix.curator.RetryPolicy;
25import com.netflix.curator.framework.CuratorFramework;
26import com.netflix.curator.framework.CuratorFrameworkFactory;
27import com.netflix.curator.framework.api.CuratorWatcher;
Jonathan Hartedd6a442013-02-20 15:22:06 -080028import com.netflix.curator.framework.recipes.cache.ChildData;
29import com.netflix.curator.framework.recipes.cache.PathChildrenCache;
30import com.netflix.curator.framework.recipes.cache.PathChildrenCache.StartMode;
Jonathan Hartbd181b62013-02-17 16:05:38 -080031import com.netflix.curator.framework.recipes.leader.LeaderLatch;
32import com.netflix.curator.framework.recipes.leader.Participant;
Jonathan Hart57080fb2013-02-21 10:55:46 -080033import com.netflix.curator.retry.RetryOneTime;
Jonathan Hartbd181b62013-02-17 16:05:38 -080034
Jonathan Hartd82f20d2013-02-21 18:04:24 -080035public class RegistryManager implements IFloodlightModule, IControllerRegistryService {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080036
Jonathan Hartd82f20d2013-02-21 18:04:24 -080037 protected static Logger log = LoggerFactory.getLogger(RegistryManager.class);
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080038 protected String mastershipId = null;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080039
Jonathan Hartbd181b62013-02-17 16:05:38 -080040 //TODO read this from configuration
41 protected String connectionString = "localhost:2181";
42 private final String namespace = "onos";
Jonathan Hartedd6a442013-02-20 15:22:06 -080043 private final String switchLatchesPath = "/switches";
Jonathan Hartbd181b62013-02-17 16:05:38 -080044
45 protected CuratorFramework client;
Jonathan Hartedd6a442013-02-20 15:22:06 -080046
47 private final String controllerPath = "/controllers";
48 protected PathChildrenCache controllerCache;
Jonathan Hartbd181b62013-02-17 16:05:38 -080049
50 protected Map<String, LeaderLatch> switchLatches;
Jonathan Hartd82f20d2013-02-21 18:04:24 -080051 protected Map<String, ControlChangeCallback> switchCallbacks;
Jonathan Hartbd181b62013-02-17 16:05:38 -080052
Jonathan Hart57080fb2013-02-21 10:55:46 -080053 protected boolean moduleEnabled = false;
54
Jonathan Hartbd181b62013-02-17 16:05:38 -080055 protected class ParamaterizedCuratorWatcher implements CuratorWatcher {
56 private String dpid;
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080057 private boolean isLeader = false;
Jonathan Hartbd181b62013-02-17 16:05:38 -080058 private String latchPath;
59
60 public ParamaterizedCuratorWatcher(String dpid, String latchPath){
61 this.dpid = dpid;
62 this.latchPath = latchPath;
63 }
64
65 @Override
Jonathan Hartedd6a442013-02-20 15:22:06 -080066 public synchronized void process(WatchedEvent event) throws Exception {
Jonathan Hartbd181b62013-02-17 16:05:38 -080067 log.debug("Watch Event: {}", event);
68
69 LeaderLatch latch = switchLatches.get(dpid);
70
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080071 if (event.getState() == KeeperState.Disconnected){
72 if (isLeader) {
73 log.debug("Disconnected while leader - lost leadership for {}", dpid);
74
75 isLeader = false;
Jonathan Hartd82f20d2013-02-21 18:04:24 -080076 switchCallbacks.get(dpid).controlChanged(HexString.toLong(dpid), false);
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080077 }
78 return;
79 }
Jonathan Hartbd181b62013-02-17 16:05:38 -080080
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080081 try {
Jonathan Hartedd6a442013-02-20 15:22:06 -080082
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080083 Participant leader = latch.getLeader();
84
85 if (leader.getId().equals(mastershipId) && !isLeader){
86 log.debug("Became leader for {}", dpid);
87
88 isLeader = true;
Jonathan Hartd82f20d2013-02-21 18:04:24 -080089 switchCallbacks.get(dpid).controlChanged(HexString.toLong(dpid), true);
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080090 }
91 else if (!leader.getId().equals(mastershipId) && isLeader){
92 log.debug("Lost leadership for {}", dpid);
93
94 isLeader = false;
Jonathan Hartd82f20d2013-02-21 18:04:24 -080095 switchCallbacks.get(dpid).controlChanged(HexString.toLong(dpid), false);
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080096 }
97 } catch (Exception e){
98 if (isLeader){
99 log.debug("Exception checking leadership status. Assume leadship lost for {}",
100 dpid);
101
102 isLeader = false;
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800103 switchCallbacks.get(dpid).controlChanged(HexString.toLong(dpid), false);
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800104 }
Jonathan Hartbd181b62013-02-17 16:05:38 -0800105 }
106
107 client.getChildren().usingWatcher(this).inBackground().forPath(latchPath);
108 //client.getChildren().usingWatcher(this).forPath(latchPath);
109 }
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800110 }
Jonathan Hartedd6a442013-02-20 15:22:06 -0800111
Jonathan Hartbd181b62013-02-17 16:05:38 -0800112
113 @Override
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800114 public void requestControl(long dpid, ControlChangeCallback cb) throws Exception {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800115
Jonathan Hart57080fb2013-02-21 10:55:46 -0800116 if (!moduleEnabled) return;
117
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800118 if (mastershipId == null){
119 throw new RuntimeException("Must set mastershipId before calling aquireMastership");
Jonathan Hartbd181b62013-02-17 16:05:38 -0800120 }
121
122 String dpidStr = HexString.toHexString(dpid);
123 String latchPath = switchLatchesPath + "/" + dpidStr;
124
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800125 if (switchLatches.get(dpidStr) != null){
126 throw new RuntimeException("Leader election for switch " + dpidStr +
127 "is already running");
128 }
129
Jonathan Hartbd181b62013-02-17 16:05:38 -0800130 LeaderLatch latch = new LeaderLatch(client, latchPath, mastershipId);
131 switchLatches.put(dpidStr, latch);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800132 switchCallbacks.put(dpidStr, cb);
133
134 try {
135 //client.getChildren().usingWatcher(watcher).inBackground().forPath(singleLatchPath);
136 client.getChildren().usingWatcher(
137 new ParamaterizedCuratorWatcher(dpidStr, latchPath))
138 .inBackground().forPath(latchPath);
139 latch.start();
140 } catch (Exception e) {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800141 log.warn("Error starting leader latch: {}", e.getMessage());
142 throw e;
Jonathan Hartbd181b62013-02-17 16:05:38 -0800143 }
144
145 }
146
147 @Override
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800148 public void releaseControl(long dpid) {
Jonathan Hart57080fb2013-02-21 10:55:46 -0800149 if (!moduleEnabled) return;
150
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800151 String dpidStr = HexString.toHexString(dpid);
152
153 LeaderLatch latch = switchLatches.get(dpidStr);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800154 if (latch == null) {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800155 log.debug("Trying to release mastership for switch we are not contesting");
Jonathan Hartbd181b62013-02-17 16:05:38 -0800156 return;
157 }
158
159 try {
160 latch.close();
161 } catch (IOException e) {
Jonathan Hart1be46262013-02-20 16:43:51 -0800162 //I think it's OK not to do anything here. Either the node got deleted correctly,
163 //or the connection went down and the node got deleted.
164 } finally {
165 switchLatches.remove(dpidStr);
166 switchCallbacks.remove(dpidStr);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800167 }
168 }
169
170 @Override
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800171 public boolean hasControl(long dpid) {
Jonathan Hart57080fb2013-02-21 10:55:46 -0800172 if (!moduleEnabled) return false;
173
Jonathan Hartbd181b62013-02-17 16:05:38 -0800174 LeaderLatch latch = switchLatches.get(HexString.toHexString(dpid));
175
176 if (latch == null) {
177 log.warn("No leader latch for dpid {}", HexString.toHexString(dpid));
178 return false;
179 }
180
Jonathan Hartbd181b62013-02-17 16:05:38 -0800181 try {
182 return latch.getLeader().getId().equals(mastershipId);
183 } catch (Exception e) {
184 //TODO swallow exception?
185 return false;
186 }
187 }
188
189 @Override
190 public void setMastershipId(String id) {
Jonathan Hartbd181b62013-02-17 16:05:38 -0800191 mastershipId = id;
192 }
193
194 @Override
195 public String getMastershipId() {
Jonathan Hartbd181b62013-02-17 16:05:38 -0800196 return mastershipId;
197 }
198
Jonathan Hartedd6a442013-02-20 15:22:06 -0800199 @Override
Jonathan Hart57080fb2013-02-21 10:55:46 -0800200 public Collection<String> getAllControllers() throws RegistryException {
201 if (!moduleEnabled) return null;
202
Jonathan Hartedd6a442013-02-20 15:22:06 -0800203 log.debug("Getting all controllers");
Jonathan Hart1be46262013-02-20 16:43:51 -0800204
Jonathan Hartedd6a442013-02-20 15:22:06 -0800205 List<String> controllers = new ArrayList<String>();
206 for (ChildData data : controllerCache.getCurrentData()){
207
208 String d = null;
209 try {
210 d = new String(data.getData(), "UTF-8");
211 } catch (UnsupportedEncodingException e) {
Jonathan Hart57080fb2013-02-21 10:55:46 -0800212 throw new RegistryException("Error encoding string", e);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800213 }
214
215 controllers.add(d);
216 }
217 return controllers;
218 }
219
220 @Override
Jonathan Hart57080fb2013-02-21 10:55:46 -0800221 public void registerController(String id) throws RegistryException {
222 if (!moduleEnabled) return;
223
Jonathan Hartedd6a442013-02-20 15:22:06 -0800224 byte bytes[] = null;
225 try {
226 bytes = id.getBytes("UTF-8");
227 } catch (UnsupportedEncodingException e1) {
Jonathan Hart57080fb2013-02-21 10:55:46 -0800228 throw new RegistryException("Error encoding string", e1);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800229 }
230
231 String path = controllerPath + "/" + id;
232
233 log.info("Registering controller with id {}", id);
234
Jonathan Hart57080fb2013-02-21 10:55:46 -0800235 //Create ephemeral node in controller registry
Jonathan Hartedd6a442013-02-20 15:22:06 -0800236 try {
237 client.create().withProtection().withMode(CreateMode.EPHEMERAL)
238 .forPath(path, bytes);
239 } catch (Exception e) {
Jonathan Hart57080fb2013-02-21 10:55:46 -0800240 throw new RegistryException("Error contacting the Zookeeper service", e);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800241 }
242 }
243
244 @Override
Jonathan Hart57080fb2013-02-21 10:55:46 -0800245 public String getControllerForSwitch(long dpid) throws RegistryException {
246 if (!moduleEnabled) return null;
Jonathan Hartedd6a442013-02-20 15:22:06 -0800247 // TODO Work out how we should store this controller/switch data.
248 // The leader latch might be a index to the /controllers collections
249 // which holds more info on the controller (how to talk to it for example).
250
251
252 String strDpid = HexString.toHexString(dpid);
253 LeaderLatch latch = switchLatches.get(strDpid);
254
255 if (latch == null){
256 log.warn("Tried to get controller for non-existent switch");
257 return null;
258 }
259
260 Participant leader = null;
261 try {
262 leader = latch.getLeader();
263 } catch (Exception e) {
Jonathan Hart57080fb2013-02-21 10:55:46 -0800264 throw new RegistryException("Error contacting the Zookeeper service", e);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800265 }
266
267 return leader.getId();
268 }
269
270 @Override
271 public Collection<Long> getSwitchesControlledByController(String controllerId) {
272 // TODO Auto-generated method stub
273 return null;
274 }
Jonathan Hartbd181b62013-02-17 16:05:38 -0800275
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800276
277 @Override
278 public Collection<Map<String, String>> getAllSwitches() {
279 // TODO Auto-generated method stub
280 return null;
281 }
282
Jonathan Hartbd181b62013-02-17 16:05:38 -0800283 /*
284 * IFloodlightModule
285 */
286
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800287 @Override
288 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hartedd6a442013-02-20 15:22:06 -0800289 Collection<Class<? extends IFloodlightService>> l =
290 new ArrayList<Class<? extends IFloodlightService>>();
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800291 l.add(IControllerRegistryService.class);
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800292 return l;
293 }
294
295 @Override
296 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
297 Map<Class<? extends IFloodlightService>, IFloodlightService> m =
298 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800299 m.put(IControllerRegistryService.class, this);
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800300 return m;
301 }
302
303 @Override
304 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
305 // no module dependencies
306 return null;
307 }
308
309 @Override
310 public void init (FloodlightModuleContext context) throws FloodlightModuleException {
Jonathan Hart57080fb2013-02-21 10:55:46 -0800311
312 //Read config to see if we should try and connect to zookeeper
313 Map<String, String> configOptions = context.getConfigParams(this);
314 String enableZookeeper = configOptions.get("enableZookeeper");
315 if (enableZookeeper != null) {
316 log.info("Enabling Mastership module - requires Zookeeper connection");
317 moduleEnabled = true;
318 }
319 else {
320 log.info("Mastership module is disabled");
321 return;
322 }
323
Jonathan Hartbd181b62013-02-17 16:05:38 -0800324 try {
325 String localHostname = java.net.InetAddress.getLocalHost().getHostName();
326 mastershipId = localHostname;
327 log.debug("Setting mastership id to {}", mastershipId);
328 } catch (UnknownHostException e) {
329 // TODO Handle this exception
330 e.printStackTrace();
331 }
332
333 switchLatches = new HashMap<String, LeaderLatch>();
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800334 switchCallbacks = new HashMap<String, ControlChangeCallback>();
Jonathan Hartbd181b62013-02-17 16:05:38 -0800335
Jonathan Hart57080fb2013-02-21 10:55:46 -0800336 //RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
337 RetryPolicy retryPolicy = new RetryOneTime(0);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800338 client = CuratorFrameworkFactory.newClient(connectionString, retryPolicy);
339
340 client.start();
341
342 client = client.usingNamespace(namespace);
343
Jonathan Hartedd6a442013-02-20 15:22:06 -0800344 controllerCache = new PathChildrenCache(client, controllerPath, true);
345
346 try {
347 controllerCache.start(StartMode.BUILD_INITIAL_CACHE);
Jonathan Hartedd6a442013-02-20 15:22:06 -0800348 } catch (Exception e) {
349 // TODO Auto-generated catch block
350 e.printStackTrace();
351 }
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800352 }
353
354 @Override
355 public void startUp (FloodlightModuleContext context) {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800356 // Nothing to be done on startup
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800357 }
Jonathan Hartd82f20d2013-02-21 18:04:24 -0800358
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800359}