blob: 46b533eb47b67d8033652ba929ba00aa314e8aff [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;
4import java.net.UnknownHostException;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -08005import java.util.ArrayList;
6import java.util.Collection;
7import java.util.HashMap;
8import java.util.Map;
9
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080010import net.floodlightcontroller.core.module.FloodlightModuleContext;
11import net.floodlightcontroller.core.module.FloodlightModuleException;
12import net.floodlightcontroller.core.module.IFloodlightModule;
13import net.floodlightcontroller.core.module.IFloodlightService;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080014
Jonathan Hartbd181b62013-02-17 16:05:38 -080015import org.apache.zookeeper.WatchedEvent;
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080016import org.apache.zookeeper.Watcher.Event.KeeperState;
Jonathan Hartbd181b62013-02-17 16:05:38 -080017import org.openflow.util.HexString;
18import org.slf4j.Logger;
19import org.slf4j.LoggerFactory;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080020
Jonathan Hartbd181b62013-02-17 16:05:38 -080021import com.netflix.curator.RetryPolicy;
22import com.netflix.curator.framework.CuratorFramework;
23import com.netflix.curator.framework.CuratorFrameworkFactory;
24import com.netflix.curator.framework.api.CuratorWatcher;
25import com.netflix.curator.framework.recipes.leader.LeaderLatch;
26import com.netflix.curator.framework.recipes.leader.Participant;
Jonathan Hartbd181b62013-02-17 16:05:38 -080027import com.netflix.curator.retry.ExponentialBackoffRetry;
28
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080029public class MastershipManager implements IFloodlightModule, IMastershipService {
30
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080031 protected static Logger log = LoggerFactory.getLogger(MastershipManager.class);
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080032 protected String mastershipId = null;
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -080033
Jonathan Hartbd181b62013-02-17 16:05:38 -080034 //TODO read this from configuration
35 protected String connectionString = "localhost:2181";
36 private final String namespace = "onos";
37 private final String switchLatchesPath = "/switchmastership";
38
39 protected CuratorFramework client;
40
41 protected Map<String, LeaderLatch> switchLatches;
42 protected Map<String, MastershipCallback> switchCallbacks;
43
Jonathan Hartbd181b62013-02-17 16:05:38 -080044 protected class ParamaterizedCuratorWatcher implements CuratorWatcher {
45 private String dpid;
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080046 private boolean isLeader = false;
Jonathan Hartbd181b62013-02-17 16:05:38 -080047 private String latchPath;
48
49 public ParamaterizedCuratorWatcher(String dpid, String latchPath){
50 this.dpid = dpid;
51 this.latchPath = latchPath;
52 }
53
54 @Override
55 public void process(WatchedEvent event) throws Exception {
56 log.debug("Watch Event: {}", event);
57
58 LeaderLatch latch = switchLatches.get(dpid);
59
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080060 if (event.getState() == KeeperState.Disconnected){
61 if (isLeader) {
62 log.debug("Disconnected while leader - lost leadership for {}", dpid);
63
64 isLeader = false;
65 switchCallbacks.get(dpid).changeCallback(HexString.toLong(dpid), false);
66 }
67 return;
68 }
Jonathan Hartbd181b62013-02-17 16:05:38 -080069
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080070 try {
71 Participant leader = latch.getLeader();
72
73 if (leader.getId().equals(mastershipId) && !isLeader){
74 log.debug("Became leader for {}", dpid);
75
76 isLeader = true;
77 switchCallbacks.get(dpid).changeCallback(HexString.toLong(dpid), true);
78 }
79 else if (!leader.getId().equals(mastershipId) && isLeader){
80 log.debug("Lost leadership for {}", dpid);
81
82 isLeader = false;
83 switchCallbacks.get(dpid).changeCallback(HexString.toLong(dpid), false);
84 }
85 } catch (Exception e){
86 if (isLeader){
87 log.debug("Exception checking leadership status. Assume leadship lost for {}",
88 dpid);
89
90 isLeader = false;
91 switchCallbacks.get(dpid).changeCallback(HexString.toLong(dpid), false);
92 }
Jonathan Hartbd181b62013-02-17 16:05:38 -080093 }
94
95 client.getChildren().usingWatcher(this).inBackground().forPath(latchPath);
96 //client.getChildren().usingWatcher(this).forPath(latchPath);
97 }
Jonathan Hartc6eee9e2013-02-18 14:58:27 -080098 }
Jonathan Hartbd181b62013-02-17 16:05:38 -080099
100 @Override
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800101 public void acquireMastership(long dpid, MastershipCallback cb) throws Exception {
102
103 if (mastershipId == null){
104 throw new RuntimeException("Must set mastershipId before calling aquireMastership");
Jonathan Hartbd181b62013-02-17 16:05:38 -0800105 }
106
107 String dpidStr = HexString.toHexString(dpid);
108 String latchPath = switchLatchesPath + "/" + dpidStr;
109
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800110 if (switchLatches.get(dpidStr) != null){
111 throw new RuntimeException("Leader election for switch " + dpidStr +
112 "is already running");
113 }
114
Jonathan Hartbd181b62013-02-17 16:05:38 -0800115 LeaderLatch latch = new LeaderLatch(client, latchPath, mastershipId);
116 switchLatches.put(dpidStr, latch);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800117 switchCallbacks.put(dpidStr, cb);
118
119 try {
120 //client.getChildren().usingWatcher(watcher).inBackground().forPath(singleLatchPath);
121 client.getChildren().usingWatcher(
122 new ParamaterizedCuratorWatcher(dpidStr, latchPath))
123 .inBackground().forPath(latchPath);
124 latch.start();
125 } catch (Exception e) {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800126 log.warn("Error starting leader latch: {}", e.getMessage());
127 throw e;
Jonathan Hartbd181b62013-02-17 16:05:38 -0800128 }
129
130 }
131
132 @Override
133 public void releaseMastership(long dpid) {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800134 String dpidStr = HexString.toHexString(dpid);
135
136 LeaderLatch latch = switchLatches.get(dpidStr);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800137 if (latch == null) {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800138 log.debug("Trying to release mastership for switch we are not contesting");
Jonathan Hartbd181b62013-02-17 16:05:38 -0800139 return;
140 }
141
142 try {
143 latch.close();
144 } catch (IOException e) {
145
146 }
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800147
148 switchLatches.remove(dpidStr);
149 switchCallbacks.remove(dpidStr);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800150 }
151
152 @Override
153 public boolean amMaster(long dpid) {
154 LeaderLatch latch = switchLatches.get(HexString.toHexString(dpid));
155
156 if (latch == null) {
157 log.warn("No leader latch for dpid {}", HexString.toHexString(dpid));
158 return false;
159 }
160
Jonathan Hartbd181b62013-02-17 16:05:38 -0800161 try {
162 return latch.getLeader().getId().equals(mastershipId);
163 } catch (Exception e) {
164 //TODO swallow exception?
165 return false;
166 }
167 }
168
169 @Override
170 public void setMastershipId(String id) {
Jonathan Hartbd181b62013-02-17 16:05:38 -0800171 mastershipId = id;
172 }
173
174 @Override
175 public String getMastershipId() {
Jonathan Hartbd181b62013-02-17 16:05:38 -0800176 return mastershipId;
177 }
178
Jonathan Hartbd181b62013-02-17 16:05:38 -0800179
180 /*
181 * IFloodlightModule
182 */
183
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800184 @Override
185 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
186 Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
187 l.add(IMastershipService.class);
188 return l;
189 }
190
191 @Override
192 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
193 Map<Class<? extends IFloodlightService>, IFloodlightService> m =
194 new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
195 m.put(IMastershipService.class, this);
196 return m;
197 }
198
199 @Override
200 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
201 // no module dependencies
202 return null;
203 }
204
205 @Override
206 public void init (FloodlightModuleContext context) throws FloodlightModuleException {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800207
Jonathan Hartbd181b62013-02-17 16:05:38 -0800208 try {
209 String localHostname = java.net.InetAddress.getLocalHost().getHostName();
210 mastershipId = localHostname;
211 log.debug("Setting mastership id to {}", mastershipId);
212 } catch (UnknownHostException e) {
213 // TODO Handle this exception
214 e.printStackTrace();
215 }
216
217 switchLatches = new HashMap<String, LeaderLatch>();
218 switchCallbacks = new HashMap<String, MastershipCallback>();
219
220 RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
221 client = CuratorFrameworkFactory.newClient(connectionString, retryPolicy);
222
223 client.start();
224
225 client = client.usingNamespace(namespace);
226
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800227 return;
228 }
229
230 @Override
231 public void startUp (FloodlightModuleContext context) {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800232 // Nothing to be done on startup
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800233 }
Jonathan Hartbd181b62013-02-17 16:05:38 -0800234
235 public static void main(String args[]){
236 FloodlightModuleContext fmc = new FloodlightModuleContext();
237 MastershipManager mm = new MastershipManager();
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800238
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800239 String id = null;
240 if (args.length > 0){
241 id = args[0];
242 log.info("Using unique id: {}", id);
Jonathan Hartbd181b62013-02-17 16:05:38 -0800243 }
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800244
Jonathan Hartbd181b62013-02-17 16:05:38 -0800245 try {
246 mm.init(fmc);
247 mm.startUp(fmc);
248
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800249 if (id != null){
250 mm.setMastershipId(id);
251 }
252
Jonathan Hartbd181b62013-02-17 16:05:38 -0800253 mm.acquireMastership(1L,
254 new MastershipCallback(){
255 @Override
256 public void changeCallback(long dpid, boolean isMaster) {
257 if (isMaster){
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800258 log.debug("Callback for becoming master for {}", HexString.toHexString(dpid));
Jonathan Hartbd181b62013-02-17 16:05:38 -0800259 }
260 else {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800261 log.debug("Callback for losing mastership for {}", HexString.toHexString(dpid));
Jonathan Hartbd181b62013-02-17 16:05:38 -0800262 }
263 }
264 });
265
266 //"Server" loop
267 while (true) {
268 Thread.sleep(60000);
269 }
270
271 } catch (FloodlightModuleException e) {
Jonathan Hartbd181b62013-02-17 16:05:38 -0800272 e.printStackTrace();
273 } catch (InterruptedException e) {
Jonathan Hartc6eee9e2013-02-18 14:58:27 -0800274 e.printStackTrace();
275 } catch (Exception e) {
Jonathan Hartbd181b62013-02-17 16:05:38 -0800276 e.printStackTrace();
277 }
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800278
Jonathan Hartbd181b62013-02-17 16:05:38 -0800279 log.debug("is master: {}", mm.amMaster(1L));
Umesh Krishnaswamyb56bb292013-02-12 20:28:27 -0800280 }
281}