Thomas Vachuska

Merge remote-tracking branch 'origin/master'

...@@ -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 }
......
...@@ -15,16 +15,18 @@ ...@@ -15,16 +15,18 @@
15 */ 15 */
16 package org.onlab.onos.cli; 16 package org.onlab.onos.cli;
17 17
18 -import org.onlab.onos.core.ApplicationId; 18 +import java.util.Comparator;
19 +
19 import org.onlab.onos.cluster.ControllerNode; 20 import org.onlab.onos.cluster.ControllerNode;
21 +import org.onlab.onos.core.ApplicationId;
22 +import org.onlab.onos.net.ConnectPoint;
20 import org.onlab.onos.net.Element; 23 import org.onlab.onos.net.Element;
21 import org.onlab.onos.net.ElementId; 24 import org.onlab.onos.net.ElementId;
22 import org.onlab.onos.net.Port; 25 import org.onlab.onos.net.Port;
23 import org.onlab.onos.net.flow.FlowRule; 26 import org.onlab.onos.net.flow.FlowRule;
27 +import org.onlab.onos.net.host.PortAddresses;
24 import org.onlab.onos.net.topology.TopologyCluster; 28 import org.onlab.onos.net.topology.TopologyCluster;
25 29
26 -import java.util.Comparator;
27 -
28 /** 30 /**
29 * Various comparators. 31 * Various comparators.
30 */ 32 */
...@@ -84,4 +86,21 @@ public final class Comparators { ...@@ -84,4 +86,21 @@ public final class Comparators {
84 } 86 }
85 }; 87 };
86 88
89 + public static final Comparator<ConnectPoint> CONNECT_POINT_COMPARATOR = new Comparator<ConnectPoint>() {
90 + @Override
91 + public int compare(ConnectPoint o1, ConnectPoint o2) {
92 + int compareId = ELEMENT_ID_COMPARATOR.compare(o1.elementId(), o2.elementId());
93 + return (compareId != 0) ?
94 + compareId :
95 + Long.signum(o1.port().toLong() - o2.port().toLong());
96 + }
97 + };
98 +
99 + public static final Comparator<PortAddresses> ADDRESSES_COMPARATOR = new Comparator<PortAddresses>() {
100 + @Override
101 + public int compare(PortAddresses arg0, PortAddresses arg1) {
102 + return CONNECT_POINT_COMPARATOR.compare(arg0.connectPoint(), arg1.connectPoint());
103 + }
104 + };
105 +
87 } 106 }
......
1 +package org.onlab.onos.cli.net;
2 +
3 +import java.util.Collections;
4 +import java.util.List;
5 +import java.util.Set;
6 +
7 +import org.apache.karaf.shell.commands.Command;
8 +import org.onlab.onos.cli.AbstractShellCommand;
9 +import org.onlab.onos.cli.Comparators;
10 +import org.onlab.onos.net.host.HostService;
11 +import org.onlab.onos.net.host.InterfaceIpAddress;
12 +import org.onlab.onos.net.host.PortAddresses;
13 +
14 +import com.google.common.collect.Lists;
15 +
16 +/**
17 + * Lists all configured address port bindings.
18 + */
19 +@Command(scope = "onos", name = "address-bindings",
20 + description = "Lists all configured address port bindings.")
21 +public class AddressBindingsListCommand extends AbstractShellCommand {
22 +
23 + private static final String FORMAT =
24 + "port=%s/%s, ip(s)=%s, mac=%s";
25 +
26 + @Override
27 + protected void execute() {
28 + HostService hostService = get(HostService.class);
29 +
30 + List<PortAddresses> addresses =
31 + Lists.newArrayList(hostService.getAddressBindings());
32 +
33 + Collections.sort(addresses, Comparators.ADDRESSES_COMPARATOR);
34 +
35 + for (PortAddresses pa : addresses) {
36 + print(FORMAT, pa.connectPoint().deviceId(), pa.connectPoint().port(),
37 + printIpAddresses(pa.ipAddresses()), pa.mac());
38 + }
39 + }
40 +
41 + private String printIpAddresses(Set<InterfaceIpAddress> addresses) {
42 + StringBuilder output = new StringBuilder("[");
43 + for (InterfaceIpAddress address : addresses) {
44 + output.append(address.ipAddress().toString());
45 + output.append("/");
46 + output.append(address.subnetAddress().prefixLength());
47 + output.append(", ");
48 + }
49 + // Remove the last comma
50 + output.delete(output.length() - 2 , output.length());
51 + output.append("]");
52 + return output.toString();
53 + }
54 +
55 +}
...@@ -169,6 +169,9 @@ ...@@ -169,6 +169,9 @@
169 <command> 169 <command>
170 <action class="org.onlab.onos.cli.net.HostsListCommand"/> 170 <action class="org.onlab.onos.cli.net.HostsListCommand"/>
171 </command> 171 </command>
172 + <command>
173 + <action class="org.onlab.onos.cli.net.AddressBindingsListCommand"/>
174 + </command>
172 175
173 <command> 176 <command>
174 <action class="org.onlab.onos.cli.net.FlowsListCommand"/> 177 <action class="org.onlab.onos.cli.net.FlowsListCommand"/>
......
...@@ -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 }
......
...@@ -29,6 +29,7 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; ...@@ -29,6 +29,7 @@ import org.apache.felix.scr.annotations.ReferenceCardinality;
29 import org.apache.felix.scr.annotations.Service; 29 import org.apache.felix.scr.annotations.Service;
30 import org.onlab.onos.cluster.ClusterService; 30 import org.onlab.onos.cluster.ClusterService;
31 import org.onlab.onos.cluster.NodeId; 31 import org.onlab.onos.cluster.NodeId;
32 +import org.onlab.onos.cluster.RoleInfo;
32 import org.onlab.onos.event.AbstractListenerRegistry; 33 import org.onlab.onos.event.AbstractListenerRegistry;
33 import org.onlab.onos.event.EventDeliveryService; 34 import org.onlab.onos.event.EventDeliveryService;
34 import org.onlab.onos.mastership.MastershipEvent; 35 import org.onlab.onos.mastership.MastershipEvent;
...@@ -58,6 +59,8 @@ import org.onlab.onos.net.provider.AbstractProviderRegistry; ...@@ -58,6 +59,8 @@ import org.onlab.onos.net.provider.AbstractProviderRegistry;
58 import org.onlab.onos.net.provider.AbstractProviderService; 59 import org.onlab.onos.net.provider.AbstractProviderService;
59 import org.slf4j.Logger; 60 import org.slf4j.Logger;
60 61
62 +import com.google.common.collect.HashMultimap;
63 +
61 /** 64 /**
62 * Provides implementation of the device SB &amp; NB APIs. 65 * Provides implementation of the device SB &amp; NB APIs.
63 */ 66 */
...@@ -159,32 +162,37 @@ public class DeviceManager ...@@ -159,32 +162,37 @@ public class DeviceManager
159 162
160 // Applies the specified role to the device; ignores NONE 163 // Applies the specified role to the device; ignores NONE
161 private void applyRole(DeviceId deviceId, MastershipRole newRole) { 164 private void applyRole(DeviceId deviceId, MastershipRole newRole) {
162 - if (!newRole.equals(MastershipRole.NONE)) { 165 + if (newRole.equals(MastershipRole.NONE)) {
163 - Device device = store.getDevice(deviceId); 166 + return;
164 - // FIXME: Device might not be there yet. (eventual consistent) 167 + }
165 - if (device == null) {
166 - return;
167 - }
168 - DeviceProvider provider = getProvider(device.providerId());
169 - if (provider != null) {
170 - provider.roleChanged(device, newRole);
171 168
172 - // only trigger event when request was sent to provider 169 + Device device = store.getDevice(deviceId);
173 - // TODO: consider removing this from Device event type? 170 + // FIXME: Device might not be there yet. (eventual consistent)
174 - post(new DeviceEvent(DEVICE_MASTERSHIP_CHANGED, device)); 171 + if (device == null) {
172 + return;
173 + }
174 +
175 + DeviceProvider provider = getProvider(device.providerId());
176 + if (provider != null) {
177 + provider.roleChanged(device, newRole);
178 + // only trigger event when request was sent to provider
179 + // TODO: consider removing this from Device event type?
180 + post(new DeviceEvent(DEVICE_MASTERSHIP_CHANGED, device));
181 +
182 + if (newRole.equals(MastershipRole.MASTER)) {
183 + provider.triggerProbe(device);
175 } 184 }
176 } 185 }
177 } 186 }
178 187
179 - // Queries a device for port information. 188 + // Check a device for control channel connectivity.
180 - private void queryPortInfo(DeviceId deviceId) { 189 + private boolean isReachable(Device device) {
181 - Device device = store.getDevice(deviceId);
182 // FIXME: Device might not be there yet. (eventual consistent) 190 // FIXME: Device might not be there yet. (eventual consistent)
183 if (device == null) { 191 if (device == null) {
184 - return; 192 + return false;
185 } 193 }
186 DeviceProvider provider = getProvider(device.providerId()); 194 DeviceProvider provider = getProvider(device.providerId());
187 - provider.triggerProbe(device); 195 + return provider.isReachable(device);
188 } 196 }
189 197
190 @Override 198 @Override
...@@ -236,7 +244,6 @@ public class DeviceManager ...@@ -236,7 +244,6 @@ public class DeviceManager
236 log.info("Device {} connected", deviceId); 244 log.info("Device {} connected", deviceId);
237 // check my Role 245 // check my Role
238 MastershipRole role = mastershipService.requestRoleFor(deviceId); 246 MastershipRole role = mastershipService.requestRoleFor(deviceId);
239 - log.info("requestedRole, became {} for {}", role, deviceId);
240 if (role != MastershipRole.MASTER) { 247 if (role != MastershipRole.MASTER) {
241 // TODO: Do we need to explicitly tell the Provider that 248 // TODO: Do we need to explicitly tell the Provider that
242 // this instance is no longer the MASTER? probably not 249 // this instance is no longer the MASTER? probably not
...@@ -383,6 +390,12 @@ public class DeviceManager ...@@ -383,6 +390,12 @@ public class DeviceManager
383 // Intercepts mastership events 390 // Intercepts mastership events
384 private class InternalMastershipListener implements MastershipListener { 391 private class InternalMastershipListener implements MastershipListener {
385 392
393 + // random cache size
394 + private final int cacheSize = 5;
395 + // temporarily stores term number + events to check for duplicates. A hack.
396 + private HashMultimap<Integer, RoleInfo> eventCache =
397 + HashMultimap.create();
398 +
386 @Override 399 @Override
387 public void event(MastershipEvent event) { 400 public void event(MastershipEvent event) {
388 final DeviceId did = event.subject(); 401 final DeviceId did = event.subject();
...@@ -391,6 +404,13 @@ public class DeviceManager ...@@ -391,6 +404,13 @@ public class DeviceManager
391 if (myNodeId.equals(event.roleInfo().master())) { 404 if (myNodeId.equals(event.roleInfo().master())) {
392 MastershipTerm term = termService.getMastershipTerm(did); 405 MastershipTerm term = termService.getMastershipTerm(did);
393 406
407 + // TODO duplicate suppression should probably occur in the MastershipManager
408 + // itself, so listeners that can't deal with duplicates don't have to
409 + // so this check themselves.
410 + if (checkDuplicate(event.roleInfo(), term.termNumber())) {
411 + return;
412 + }
413 +
394 if (!myNodeId.equals(term.master())) { 414 if (!myNodeId.equals(term.master())) {
395 // something went wrong in consistency, let go 415 // something went wrong in consistency, let go
396 log.warn("Mastership has changed after this event." 416 log.warn("Mastership has changed after this event."
...@@ -405,14 +425,16 @@ public class DeviceManager ...@@ -405,14 +425,16 @@ public class DeviceManager
405 // only set the new term if I am the master 425 // only set the new term if I am the master
406 deviceClockProviderService.setMastershipTerm(did, term); 426 deviceClockProviderService.setMastershipTerm(did, term);
407 427
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 428 // if the device is null here, we are the first master to claim the
413 // device. No worries, the DeviceManager will create one soon. 429 // device. No worries, the DeviceManager will create one soon.
414 Device device = getDevice(did); 430 Device device = getDevice(did);
415 if ((device != null) && !isAvailable(did)) { 431 if ((device != null) && !isAvailable(did)) {
432 + if (!isReachable(device)) {
433 + log.warn("Device {} has disconnected after this event", did);
434 + mastershipService.relinquishMastership(did);
435 + applyRole(did, MastershipRole.STANDBY);
436 + return;
437 + }
416 //flag the device as online. Is there a better way to do this? 438 //flag the device as online. Is there a better way to do this?
417 DeviceEvent devEvent = store.createOrUpdateDevice(device.providerId(), did, 439 DeviceEvent devEvent = store.createOrUpdateDevice(device.providerId(), did,
418 new DefaultDeviceDescription( 440 new DefaultDeviceDescription(
...@@ -422,12 +444,32 @@ public class DeviceManager ...@@ -422,12 +444,32 @@ public class DeviceManager
422 post(devEvent); 444 post(devEvent);
423 } 445 }
424 applyRole(did, MastershipRole.MASTER); 446 applyRole(did, MastershipRole.MASTER);
425 - // re-collect device information to fix potential staleness
426 - queryPortInfo(did);
427 } else if (event.roleInfo().backups().contains(myNodeId)) { 447 } else if (event.roleInfo().backups().contains(myNodeId)) {
448 + if (!isReachable(getDevice(did))) {
449 + log.warn("Device {} has disconnected after this event", did);
450 + mastershipService.relinquishMastership(did);
451 + }
428 applyRole(did, MastershipRole.STANDBY); 452 applyRole(did, MastershipRole.STANDBY);
429 } 453 }
430 } 454 }
455 +
456 + // checks for duplicate event, returning true if one is found.
457 + private boolean checkDuplicate(RoleInfo roleInfo, int term) {
458 + synchronized (eventCache) {
459 + if (eventCache.get(term).contains(roleInfo)) {
460 + log.info("duplicate event detected; ignoring");
461 + return true;
462 + } else {
463 + eventCache.put(term, roleInfo);
464 + // purge by-term oldest entries to keep the cache size under limit
465 + if (eventCache.size() > cacheSize) {
466 + eventCache.removeAll(term - cacheSize);
467 + }
468 + return false;
469 + }
470 + }
471 + }
472 +
431 } 473 }
432 474
433 // Store delegate to re-post events emitted from the store. 475 // Store delegate to re-post events emitted from the store.
......
...@@ -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 }
......