blob: f4230aeb45893bff510bf85805bb2bae22d38c57 [file] [log] [blame]
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -08001package net.floodlightcontroller.mastership;
2
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 Hartbd181b62013-02-17 16:05:38 -080033import com.netflix.curator.retry.ExponentialBackoffRetry;
34
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080035public class MastershipManager implements IFloodlightModule, IMastershipService {
36
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080037 protected static Logger log = LoggerFactory.getLogger(MastershipManager.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;
51 protected Map<String, MastershipCallback> switchCallbacks;
52
Jonathan Hartbd181b62013-02-17 16:05:38 -080053 protected class ParamaterizedCuratorWatcher implements CuratorWatcher {
54 private String dpid;
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080055 private boolean isLeader = false;
Jonathan Hartbd181b62013-02-17 16:05:38 -080056 private String latchPath;
57
58 public ParamaterizedCuratorWatcher(String dpid, String latchPath){
59 this.dpid = dpid;
60 this.latchPath = latchPath;
61 }
62
63 @Override
Jonathan Hartedd6a442013-02-20 15:22:06 -080064 public synchronized void process(WatchedEvent event) throws Exception {
Jonathan Hartbd181b62013-02-17 16:05:38 -080065 log.debug("Watch Event: {}", event);
66
67 LeaderLatch latch = switchLatches.get(dpid);
68
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080069 if (event.getState() == KeeperState.Disconnected){
70 if (isLeader) {
71 log.debug("Disconnected while leader - lost leadership for {}", dpid);
72
73 isLeader = false;
74 switchCallbacks.get(dpid).changeCallback(HexString.toLong(dpid), false);
75 }
76 return;
77 }
Jonathan Hartbd181b62013-02-17 16:05:38 -080078
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080079 try {
Jonathan Hartedd6a442013-02-20 15:22:06 -080080
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080081 Participant leader = latch.getLeader();
82
83 if (leader.getId().equals(mastershipId) && !isLeader){
84 log.debug("Became leader for {}", dpid);
85
86 isLeader = true;
87 switchCallbacks.get(dpid).changeCallback(HexString.toLong(dpid), true);
88 }
89 else if (!leader.getId().equals(mastershipId) && isLeader){
90 log.debug("Lost leadership for {}", dpid);
91
92 isLeader = false;
93 switchCallbacks.get(dpid).changeCallback(HexString.toLong(dpid), false);
94 }
95 } catch (Exception e){
96 if (isLeader){
97 log.debug("Exception checking leadership status. Assume leadship lost for {}",
98 dpid);
99
100 isLeader = false;
101 switchCallbacks.get(dpid).changeCallback(HexString.toLong(dpid), false);
102 }
Jonathan Hartbd181b62013-02-17 16:05:38 -0800103 }
104
105 client.getChildren().usingWatcher(this).inBackground().forPath(latchPath);
106 //client.getChildren().usingWatcher(this).forPath(latchPath);
107 }
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800108 }
Jonathan Hartedd6a442013-02-20 15:22:06 -0800109
Jonathan Hartbd181b62013-02-17 16:05:38 -0800110
111 @Override
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800112 public void acquireMastership(long dpid, MastershipCallback cb) throws Exception {
113
114 if (mastershipId == null){
115 throw new RuntimeException("Must set mastershipId before calling aquireMastership");
Jonathan Hartbd181b62013-02-17 16:05:38 -0800116 }
117
118 String dpidStr = HexString.toHexString(dpid);
119 String latchPath = switchLatchesPath + "/" + dpidStr;
120
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800121 if (switchLatches.get(dpidStr) != null){
122 throw new RuntimeException("Leader election for switch " + dpidStr +
123 "is already running");
124 }
125
Jonathan Hartbd181b62013-02-17 16:05:38 -0800126 LeaderLatch latch = new LeaderLatch(client, latchPath, mastershipId);
127 switchLatches.put(dpidStr, latch);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800128 switchCallbacks.put(dpidStr, cb);
129
130 try {
131 //client.getChildren().usingWatcher(watcher).inBackground().forPath(singleLatchPath);
132 client.getChildren().usingWatcher(
133 new ParamaterizedCuratorWatcher(dpidStr, latchPath))
134 .inBackground().forPath(latchPath);
135 latch.start();
136 } catch (Exception e) {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800137 log.warn("Error starting leader latch: {}", e.getMessage());
138 throw e;
Jonathan Hartbd181b62013-02-17 16:05:38 -0800139 }
140
141 }
142
143 @Override
144 public void releaseMastership(long dpid) {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800145 String dpidStr = HexString.toHexString(dpid);
146
147 LeaderLatch latch = switchLatches.get(dpidStr);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800148 if (latch == null) {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800149 log.debug("Trying to release mastership for switch we are not contesting");
Jonathan Hartbd181b62013-02-17 16:05:38 -0800150 return;
151 }
152
153 try {
154 latch.close();
155 } catch (IOException e) {
156
157 }
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800158
159 switchLatches.remove(dpidStr);
160 switchCallbacks.remove(dpidStr);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800161 }
162
163 @Override
164 public boolean amMaster(long dpid) {
165 LeaderLatch latch = switchLatches.get(HexString.toHexString(dpid));
166
167 if (latch == null) {
168 log.warn("No leader latch for dpid {}", HexString.toHexString(dpid));
169 return false;
170 }
171
Jonathan Hartbd181b62013-02-17 16:05:38 -0800172 try {
173 return latch.getLeader().getId().equals(mastershipId);
174 } catch (Exception e) {
175 //TODO swallow exception?
176 return false;
177 }
178 }
179
180 @Override
181 public void setMastershipId(String id) {
Jonathan Hartbd181b62013-02-17 16:05:38 -0800182 mastershipId = id;
183 }
184
185 @Override
186 public String getMastershipId() {
Jonathan Hartbd181b62013-02-17 16:05:38 -0800187 return mastershipId;
188 }
189
Jonathan Hartedd6a442013-02-20 15:22:06 -0800190 @Override
191 public Collection<String> getAllControllers() {
192 // TODO Auto-generated method stub
193 log.debug("Getting all controllers");
194 List<String> controllers = new ArrayList<String>();
195 for (ChildData data : controllerCache.getCurrentData()){
196
197 String d = null;
198 try {
199 d = new String(data.getData(), "UTF-8");
200 } catch (UnsupportedEncodingException e) {
201 // TODO unlikely(throw exception)
202 e.printStackTrace();
203 }
204
205 controllers.add(d);
206 }
207 return controllers;
208 }
209
210 @Override
211 public void registerController(String id) {
212 // TODO Auto-generated method stub
213 byte bytes[] = null;
214 try {
215 bytes = id.getBytes("UTF-8");
216 } catch (UnsupportedEncodingException e1) {
217 // TODO Throw some exception (very unlikely this will happen)
218 e1.printStackTrace();
219 }
220
221 String path = controllerPath + "/" + id;
222
223 log.info("Registering controller with id {}", id);
224
225 //Create ephemeral node with my id
226 try {
227 client.create().withProtection().withMode(CreateMode.EPHEMERAL)
228 .forPath(path, bytes);
229 } catch (Exception e) {
230 // TODO Auto-generated catch block
231 // TODO Make an exception that will be thrown here
232 e.printStackTrace();
233 }
234 }
235
236 @Override
237 public String getControllerForSwitch(long dpid) {
238 // TODO Work out how we should store this controller/switch data.
239 // The leader latch might be a index to the /controllers collections
240 // which holds more info on the controller (how to talk to it for example).
241
242
243 String strDpid = HexString.toHexString(dpid);
244 LeaderLatch latch = switchLatches.get(strDpid);
245
246 if (latch == null){
247 log.warn("Tried to get controller for non-existent switch");
248 return null;
249 }
250
251 Participant leader = null;
252 try {
253 leader = latch.getLeader();
254 } catch (Exception e) {
255 // TODO Zookeeper issue, throw exception
256 e.printStackTrace();
257 }
258
259 return leader.getId();
260 }
261
262 @Override
263 public Collection<Long> getSwitchesControlledByController(String controllerId) {
264 // TODO Auto-generated method stub
265 return null;
266 }
Jonathan Hartbd181b62013-02-17 16:05:38 -0800267
268 /*
269 * IFloodlightModule
270 */
271
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800272 @Override
273 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hartedd6a442013-02-20 15:22:06 -0800274 Collection<Class<? extends IFloodlightService>> l =
275 new ArrayList<Class<? extends IFloodlightService>>();
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800276 l.add(IMastershipService.class);
277 return l;
278 }
279
280 @Override
281 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
282 Map<Class<? extends IFloodlightService>, IFloodlightService> m =
283 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
284 m.put(IMastershipService.class, this);
285 return m;
286 }
287
288 @Override
289 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
290 // no module dependencies
291 return null;
292 }
293
294 @Override
295 public void init (FloodlightModuleContext context) throws FloodlightModuleException {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800296
Jonathan Hartbd181b62013-02-17 16:05:38 -0800297 try {
298 String localHostname = java.net.InetAddress.getLocalHost().getHostName();
299 mastershipId = localHostname;
300 log.debug("Setting mastership id to {}", mastershipId);
301 } catch (UnknownHostException e) {
302 // TODO Handle this exception
303 e.printStackTrace();
304 }
305
306 switchLatches = new HashMap<String, LeaderLatch>();
307 switchCallbacks = new HashMap<String, MastershipCallback>();
308
309 RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
310 client = CuratorFrameworkFactory.newClient(connectionString, retryPolicy);
311
312 client.start();
313
314 client = client.usingNamespace(namespace);
315
Jonathan Hartedd6a442013-02-20 15:22:06 -0800316 controllerCache = new PathChildrenCache(client, controllerPath, true);
317
318 try {
319 controllerCache.start(StartMode.BUILD_INITIAL_CACHE);
320
321
322 } catch (Exception e) {
323 // TODO Auto-generated catch block
324 e.printStackTrace();
325 }
326
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800327 }
328
329 @Override
330 public void startUp (FloodlightModuleContext context) {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800331 // Nothing to be done on startup
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800332 }
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800333}