Ayaka Koshibe

avoid transient changes to MastershipStore from being posted as events

Change-Id: Id033cf50f865e44439138f5b3814ebaedb832b73
...@@ -372,4 +372,8 @@ public class OpticalConfigProvider extends AbstractProvider implements DevicePro ...@@ -372,4 +372,8 @@ public class OpticalConfigProvider extends AbstractProvider implements DevicePro
372 // TODO Auto-generated method stub. 372 // TODO Auto-generated method stub.
373 } 373 }
374 374
375 + @Override
376 + public boolean isReachable(Device device) {
377 + return false;
378 + }
375 } 379 }
......
...@@ -47,4 +47,11 @@ public interface DeviceProvider extends Provider { ...@@ -47,4 +47,11 @@ public interface DeviceProvider extends Provider {
47 */ 47 */
48 void roleChanged(Device device, MastershipRole newRole); 48 void roleChanged(Device device, MastershipRole newRole);
49 49
50 + /**
51 + * Checks the reachability (connectivity) of a device from this provider.
52 + *
53 + * @param device device to check
54 + * @return true if reachable, false otherwise
55 + */
56 + boolean isReachable(Device device);
50 } 57 }
......
...@@ -97,10 +97,20 @@ implements MastershipService, MastershipAdminService { ...@@ -97,10 +97,20 @@ implements MastershipService, MastershipAdminService {
97 checkNotNull(role, ROLE_NULL); 97 checkNotNull(role, ROLE_NULL);
98 98
99 MastershipEvent event = null; 99 MastershipEvent event = null;
100 - if (role.equals(MastershipRole.MASTER)) { 100 +
101 - event = store.setMaster(nodeId, deviceId); 101 + switch (role) {
102 - } else { 102 + case MASTER:
103 - event = store.setStandby(nodeId, deviceId); 103 + event = store.setMaster(nodeId, deviceId);
104 + break;
105 + case STANDBY:
106 + event = store.setStandby(nodeId, deviceId);
107 + break;
108 + case NONE:
109 + event = store.relinquishRole(nodeId, deviceId);
110 + break;
111 + default:
112 + log.info("Unknown role; ignoring");
113 + return;
104 } 114 }
105 115
106 if (event != null) { 116 if (event != null) {
...@@ -259,6 +269,10 @@ implements MastershipService, MastershipAdminService { ...@@ -259,6 +269,10 @@ implements MastershipService, MastershipAdminService {
259 269
260 @Override 270 @Override
261 public void notify(MastershipEvent event) { 271 public void notify(MastershipEvent event) {
272 + if (clusterService.getLocalNode().id().equals(event.roleInfo().master())) {
273 + log.info("ignoring locally-generated event {}", event);
274 + // return;
275 + }
262 log.info("dispatching mastership event {}", event); 276 log.info("dispatching mastership event {}", event);
263 eventDispatcher.post(event); 277 eventDispatcher.post(event);
264 } 278 }
......
...@@ -159,32 +159,37 @@ public class DeviceManager ...@@ -159,32 +159,37 @@ public class DeviceManager
159 159
160 // Applies the specified role to the device; ignores NONE 160 // Applies the specified role to the device; ignores NONE
161 private void applyRole(DeviceId deviceId, MastershipRole newRole) { 161 private void applyRole(DeviceId deviceId, MastershipRole newRole) {
162 - if (!newRole.equals(MastershipRole.NONE)) { 162 + if (newRole.equals(MastershipRole.NONE)) {
163 - Device device = store.getDevice(deviceId); 163 + return;
164 - // FIXME: Device might not be there yet. (eventual consistent) 164 + }
165 - if (device == null) {
166 - return;
167 - }
168 - DeviceProvider provider = getProvider(device.providerId());
169 - if (provider != null) {
170 - provider.roleChanged(device, newRole);
171 165
172 - // only trigger event when request was sent to provider 166 + Device device = store.getDevice(deviceId);
173 - // TODO: consider removing this from Device event type? 167 + // FIXME: Device might not be there yet. (eventual consistent)
174 - post(new DeviceEvent(DEVICE_MASTERSHIP_CHANGED, device)); 168 + if (device == null) {
169 + return;
170 + }
171 +
172 + DeviceProvider provider = getProvider(device.providerId());
173 + if (provider != null) {
174 + provider.roleChanged(device, newRole);
175 + // only trigger event when request was sent to provider
176 + // TODO: consider removing this from Device event type?
177 + post(new DeviceEvent(DEVICE_MASTERSHIP_CHANGED, device));
178 +
179 + if (newRole.equals(MastershipRole.MASTER)) {
180 + provider.triggerProbe(device);
175 } 181 }
176 } 182 }
177 } 183 }
178 184
179 - // Queries a device for port information. 185 + // Check a device for control channel connectivity.
180 - private void queryPortInfo(DeviceId deviceId) { 186 + private boolean isReachable(Device device) {
181 - Device device = store.getDevice(deviceId);
182 // FIXME: Device might not be there yet. (eventual consistent) 187 // FIXME: Device might not be there yet. (eventual consistent)
183 if (device == null) { 188 if (device == null) {
184 - return; 189 + return false;
185 } 190 }
186 DeviceProvider provider = getProvider(device.providerId()); 191 DeviceProvider provider = getProvider(device.providerId());
187 - provider.triggerProbe(device); 192 + return provider.isReachable(device);
188 } 193 }
189 194
190 @Override 195 @Override
...@@ -236,7 +241,6 @@ public class DeviceManager ...@@ -236,7 +241,6 @@ public class DeviceManager
236 log.info("Device {} connected", deviceId); 241 log.info("Device {} connected", deviceId);
237 // check my Role 242 // check my Role
238 MastershipRole role = mastershipService.requestRoleFor(deviceId); 243 MastershipRole role = mastershipService.requestRoleFor(deviceId);
239 - log.info("requestedRole, became {} for {}", role, deviceId);
240 if (role != MastershipRole.MASTER) { 244 if (role != MastershipRole.MASTER) {
241 // TODO: Do we need to explicitly tell the Provider that 245 // TODO: Do we need to explicitly tell the Provider that
242 // this instance is no longer the MASTER? probably not 246 // this instance is no longer the MASTER? probably not
...@@ -405,14 +409,16 @@ public class DeviceManager ...@@ -405,14 +409,16 @@ public class DeviceManager
405 // only set the new term if I am the master 409 // only set the new term if I am the master
406 deviceClockProviderService.setMastershipTerm(did, term); 410 deviceClockProviderService.setMastershipTerm(did, term);
407 411
408 - // FIXME: we should check that the device is connected on our end.
409 - // currently, this is not straight forward as the actual switch
410 - // implementation is hidden from the registry. Maybe we can ask the
411 - // provider.
412 // if the device is null here, we are the first master to claim the 412 // if the device is null here, we are the first master to claim the
413 // device. No worries, the DeviceManager will create one soon. 413 // device. No worries, the DeviceManager will create one soon.
414 Device device = getDevice(did); 414 Device device = getDevice(did);
415 if ((device != null) && !isAvailable(did)) { 415 if ((device != null) && !isAvailable(did)) {
416 + if (!isReachable(device)) {
417 + log.warn("Device {} has disconnected after this event", did);
418 + mastershipService.relinquishMastership(did);
419 + applyRole(did, MastershipRole.STANDBY);
420 + return;
421 + }
416 //flag the device as online. Is there a better way to do this? 422 //flag the device as online. Is there a better way to do this?
417 DeviceEvent devEvent = store.createOrUpdateDevice(device.providerId(), did, 423 DeviceEvent devEvent = store.createOrUpdateDevice(device.providerId(), did,
418 new DefaultDeviceDescription( 424 new DefaultDeviceDescription(
...@@ -422,9 +428,11 @@ public class DeviceManager ...@@ -422,9 +428,11 @@ public class DeviceManager
422 post(devEvent); 428 post(devEvent);
423 } 429 }
424 applyRole(did, MastershipRole.MASTER); 430 applyRole(did, MastershipRole.MASTER);
425 - // re-collect device information to fix potential staleness
426 - queryPortInfo(did);
427 } else if (event.roleInfo().backups().contains(myNodeId)) { 431 } else if (event.roleInfo().backups().contains(myNodeId)) {
432 + if (!isReachable(getDevice(did))) {
433 + log.warn("Device {} has disconnected after this event", did);
434 + mastershipService.relinquishMastership(did);
435 + }
428 applyRole(did, MastershipRole.STANDBY); 436 applyRole(did, MastershipRole.STANDBY);
429 } 437 }
430 } 438 }
......
...@@ -278,6 +278,11 @@ public class DeviceManagerTest { ...@@ -278,6 +278,11 @@ public class DeviceManagerTest {
278 deviceReceived = device; 278 deviceReceived = device;
279 roleReceived = newRole; 279 roleReceived = newRole;
280 } 280 }
281 +
282 + @Override
283 + public boolean isReachable(Device device) {
284 + return false;
285 + }
281 } 286 }
282 287
283 private static class TestListener implements DeviceListener { 288 private static class TestListener implements DeviceListener {
......
...@@ -272,6 +272,10 @@ implements MastershipStore { ...@@ -272,6 +272,10 @@ implements MastershipStore {
272 switch (role) { 272 switch (role) {
273 case MASTER: 273 case MASTER:
274 event = reelect(nodeId, deviceId, rv); 274 event = reelect(nodeId, deviceId, rv);
275 + if (event != null) {
276 + Integer term = terms.get(deviceId);
277 + terms.put(deviceId, ++term);
278 + }
275 //fall through to reinforce relinquishment 279 //fall through to reinforce relinquishment
276 case STANDBY: 280 case STANDBY:
277 //fall through to reinforce relinquishment 281 //fall through to reinforce relinquishment
...@@ -304,15 +308,11 @@ implements MastershipStore { ...@@ -304,15 +308,11 @@ implements MastershipStore {
304 if (backup == null) { 308 if (backup == null) {
305 log.info("{} giving up and going to NONE for {}", current, deviceId); 309 log.info("{} giving up and going to NONE for {}", current, deviceId);
306 rv.remove(MASTER, current); 310 rv.remove(MASTER, current);
307 - roleMap.put(deviceId, rv);
308 return null; 311 return null;
309 } else { 312 } else {
310 log.info("{} trying to pass mastership for {} to {}", current, deviceId, backup); 313 log.info("{} trying to pass mastership for {} to {}", current, deviceId, backup);
311 rv.replace(current, backup, MASTER); 314 rv.replace(current, backup, MASTER);
312 rv.reassign(backup, STANDBY, NONE); 315 rv.reassign(backup, STANDBY, NONE);
313 - roleMap.put(deviceId, rv);
314 - Integer term = terms.get(deviceId);
315 - terms.put(deviceId, ++term);
316 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo()); 316 return new MastershipEvent(MASTER_CHANGED, deviceId, rv.roleInfo());
317 } 317 }
318 } 318 }
...@@ -366,7 +366,7 @@ implements MastershipStore { ...@@ -366,7 +366,7 @@ implements MastershipStore {
366 366
367 @Override 367 @Override
368 public void entryUpdated(EntryEvent<DeviceId, RoleValue> event) { 368 public void entryUpdated(EntryEvent<DeviceId, RoleValue> event) {
369 - 369 + // this subsumes entryAdded event
370 notifyDelegate(new MastershipEvent( 370 notifyDelegate(new MastershipEvent(
371 MASTER_CHANGED, event.getKey(), event.getValue().roleInfo())); 371 MASTER_CHANGED, event.getKey(), event.getValue().roleInfo()));
372 } 372 }
......
...@@ -103,22 +103,31 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr ...@@ -103,22 +103,31 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
103 LOG.info("Stopped"); 103 LOG.info("Stopped");
104 } 104 }
105 105
106 - @Override
107 - public void triggerProbe(Device device) {
108 - LOG.info("Triggering probe on device {}", device.id());
109 106
110 - // 1. check device liveness 107 + @Override
108 + public boolean isReachable(Device device) {
111 // FIXME if possible, we might want this to be part of 109 // FIXME if possible, we might want this to be part of
112 // OpenFlowSwitch interface so the driver interface isn't misused. 110 // OpenFlowSwitch interface so the driver interface isn't misused.
113 OpenFlowSwitch sw = controller.getSwitch(dpid(device.id().uri())); 111 OpenFlowSwitch sw = controller.getSwitch(dpid(device.id().uri()));
114 - if (sw == null || 112 + if (sw == null || !((OpenFlowSwitchDriver) sw).isConnected()) {
115 - !((OpenFlowSwitchDriver) sw).isConnected()) { 113 + return false;
116 - LOG.error("Failed to probe device {} on sw={}", device, sw);
117 - providerService.deviceDisconnected(device.id());
118 - return;
119 } 114 }
115 + return true;
116 + //return checkChannel(device, sw);
117 + }
118 +
119 + @Override
120 + public void triggerProbe(Device device) {
121 + LOG.info("Triggering probe on device {}", device.id());
122 +
123 + OpenFlowSwitch sw = controller.getSwitch(dpid(device.id().uri()));
124 + //if (!checkChannel(device, sw)) {
125 + // LOG.error("Failed to probe device {} on sw={}", device, sw);
126 + // providerService.deviceDisconnected(device.id());
127 + //return;
128 + //}
120 129
121 - // 2. Prompt an update of port information. Do we have an XID for this? 130 + // Prompt an update of port information. We can use any XID for this.
122 OFFactory fact = sw.factory(); 131 OFFactory fact = sw.factory();
123 switch (fact.getVersion()) { 132 switch (fact.getVersion()) {
124 case OF_10: 133 case OF_10:
...@@ -132,6 +141,16 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr ...@@ -132,6 +141,16 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr
132 } 141 }
133 } 142 }
134 143
144 + // Checks if the OF channel is connected.
145 + //private boolean checkChannel(Device device, OpenFlowSwitch sw) {
146 + // FIXME if possible, we might want this to be part of
147 + // OpenFlowSwitch interface so the driver interface isn't misused.
148 + // if (sw == null || !((OpenFlowSwitchDriver) sw).isConnected()) {
149 + // return false;
150 + // }
151 + // return true;
152 + // }
153 +
135 @Override 154 @Override
136 public void roleChanged(Device device, MastershipRole newRole) { 155 public void roleChanged(Device device, MastershipRole newRole) {
137 switch (newRole) { 156 switch (newRole) {
......
...@@ -226,4 +226,9 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider { ...@@ -226,4 +226,9 @@ class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
226 public ProviderId id() { 226 public ProviderId id() {
227 return PID; 227 return PID;
228 } 228 }
229 +
230 + @Override
231 + public boolean isReachable(Device device) {
232 + return false;
233 + }
229 } 234 }
......