Committed by
Gerrit Code Review
ONOS-4422 Implemented device discovery in Bmv2 device provider and other
improvements - Added listener for hello messages received from Bmv2 devices - Added a periodic poller task to check device reachability and port information updates - Avoids periodically re-connecting the device if it is already available in the core - Fixed minor bug in Bmv2ThriftClient Change-Id: I416d1880773e11b2ac6fa062d8be2b8f280786fb
Showing
3 changed files
with
171 additions
and
69 deletions
| ... | @@ -80,9 +80,9 @@ public final class Bmv2ThriftClient implements Bmv2Client { | ... | @@ -80,9 +80,9 @@ public final class Bmv2ThriftClient implements Bmv2Client { |
| 80 | // Seconds after a client is expired (and connection closed) in the cache. | 80 | // Seconds after a client is expired (and connection closed) in the cache. |
| 81 | private static final int CLIENT_CACHE_TIMEOUT = 60; | 81 | private static final int CLIENT_CACHE_TIMEOUT = 60; |
| 82 | // Number of connection retries after a network error. | 82 | // Number of connection retries after a network error. |
| 83 | - private static final int NUM_CONNECTION_RETRIES = 10; | 83 | + private static final int NUM_CONNECTION_RETRIES = 3; |
| 84 | // Time between retries in milliseconds. | 84 | // Time between retries in milliseconds. |
| 85 | - private static final int TIME_BETWEEN_RETRIES = 200; | 85 | + private static final int TIME_BETWEEN_RETRIES = 300; |
| 86 | 86 | ||
| 87 | // Static client cache where clients are removed after a predefined timeout. | 87 | // Static client cache where clients are removed after a predefined timeout. |
| 88 | private static final LoadingCache<DeviceId, Bmv2ThriftClient> | 88 | private static final LoadingCache<DeviceId, Bmv2ThriftClient> |
| ... | @@ -125,6 +125,15 @@ public final class Bmv2ThriftClient implements Bmv2Client { | ... | @@ -125,6 +125,15 @@ public final class Bmv2ThriftClient implements Bmv2Client { |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | /** | 127 | /** |
| 128 | + * Force a close of the transport session (if one is open) with the given device. | ||
| 129 | + * | ||
| 130 | + * @param deviceId device id | ||
| 131 | + */ | ||
| 132 | + public static void forceDisconnectOf(DeviceId deviceId) { | ||
| 133 | + CLIENT_CACHE.invalidate(deviceId); | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + /** | ||
| 128 | * Pings the device. Returns true if the device is reachable, | 137 | * Pings the device. Returns true if the device is reachable, |
| 129 | * false otherwise. | 138 | * false otherwise. |
| 130 | * | 139 | * |
| ... | @@ -392,7 +401,7 @@ public final class Bmv2ThriftClient implements Bmv2Client { | ... | @@ -392,7 +401,7 @@ public final class Bmv2ThriftClient implements Bmv2Client { |
| 392 | LOG.debug("Packet transmission requested! > portNumber={}, packet={}", portNumber, packet); | 401 | LOG.debug("Packet transmission requested! > portNumber={}, packet={}", portNumber, packet); |
| 393 | } catch (TException e) { | 402 | } catch (TException e) { |
| 394 | LOG.debug("Exception while requesting packet transmission: {} > portNumber={}, packet={}", | 403 | LOG.debug("Exception while requesting packet transmission: {} > portNumber={}, packet={}", |
| 395 | - portNumber, packet); | 404 | + e, portNumber, packet); |
| 396 | throw new Bmv2RuntimeException(e.getMessage(), e); | 405 | throw new Bmv2RuntimeException(e.getMessage(), e); |
| 397 | } | 406 | } |
| 398 | } | 407 | } | ... | ... |
| ... | @@ -173,7 +173,12 @@ public final class SafeThriftClient { | ... | @@ -173,7 +173,12 @@ public final class SafeThriftClient { |
| 173 | private static void reconnectOrThrowException(TTransport transport, int maxRetries, long timeBetweenRetries) | 173 | private static void reconnectOrThrowException(TTransport transport, int maxRetries, long timeBetweenRetries) |
| 174 | throws TTransportException { | 174 | throws TTransportException { |
| 175 | int errors = 0; | 175 | int errors = 0; |
| 176 | - transport.close(); | 176 | + try { |
| 177 | + transport.close(); | ||
| 178 | + } catch (Exception e) { | ||
| 179 | + // Thrift seems to have a bug where if the transport is already closed a SocketException is thrown. | ||
| 180 | + // However, such an exception is not advertised by .close(), hence the general-purpose catch. | ||
| 181 | + } | ||
| 177 | 182 | ||
| 178 | while (errors < maxRetries) { | 183 | while (errors < maxRetries) { |
| 179 | try { | 184 | try { |
| ... | @@ -182,7 +187,7 @@ public final class SafeThriftClient { | ... | @@ -182,7 +187,7 @@ public final class SafeThriftClient { |
| 182 | LOG.debug("Reconnection successful"); | 187 | LOG.debug("Reconnection successful"); |
| 183 | break; | 188 | break; |
| 184 | } catch (TTransportException e) { | 189 | } catch (TTransportException e) { |
| 185 | - LOG.error("Error while reconnecting:", e); | 190 | + LOG.debug("Error while reconnecting:", e); |
| 186 | errors++; | 191 | errors++; |
| 187 | 192 | ||
| 188 | if (errors < maxRetries) { | 193 | if (errors < maxRetries) { | ... | ... |
| ... | @@ -16,11 +16,17 @@ | ... | @@ -16,11 +16,17 @@ |
| 16 | 16 | ||
| 17 | package org.onosproject.provider.bmv2.device.impl; | 17 | package org.onosproject.provider.bmv2.device.impl; |
| 18 | 18 | ||
| 19 | -import com.google.common.collect.Sets; | 19 | +import com.google.common.collect.Maps; |
| 20 | import org.apache.felix.scr.annotations.Component; | 20 | import org.apache.felix.scr.annotations.Component; |
| 21 | import org.apache.felix.scr.annotations.Reference; | 21 | import org.apache.felix.scr.annotations.Reference; |
| 22 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 22 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
| 23 | +import org.jboss.netty.util.HashedWheelTimer; | ||
| 24 | +import org.jboss.netty.util.Timeout; | ||
| 25 | +import org.jboss.netty.util.TimerTask; | ||
| 23 | import org.onlab.packet.ChassisId; | 26 | import org.onlab.packet.ChassisId; |
| 27 | +import org.onlab.util.Timer; | ||
| 28 | +import org.onosproject.bmv2.api.runtime.Bmv2ControlPlaneServer; | ||
| 29 | +import org.onosproject.bmv2.api.runtime.Bmv2Device; | ||
| 24 | import org.onosproject.common.net.AbstractDeviceProvider; | 30 | import org.onosproject.common.net.AbstractDeviceProvider; |
| 25 | import org.onosproject.core.ApplicationId; | 31 | import org.onosproject.core.ApplicationId; |
| 26 | import org.onosproject.core.CoreService; | 32 | import org.onosproject.core.CoreService; |
| ... | @@ -40,17 +46,20 @@ import org.onosproject.net.config.NetworkConfigRegistry; | ... | @@ -40,17 +46,20 @@ import org.onosproject.net.config.NetworkConfigRegistry; |
| 40 | import org.onosproject.net.device.DefaultDeviceDescription; | 46 | import org.onosproject.net.device.DefaultDeviceDescription; |
| 41 | import org.onosproject.net.device.DeviceDescription; | 47 | import org.onosproject.net.device.DeviceDescription; |
| 42 | import org.onosproject.net.device.DeviceService; | 48 | import org.onosproject.net.device.DeviceService; |
| 49 | +import org.onosproject.net.device.PortDescription; | ||
| 43 | import org.onosproject.net.provider.ProviderId; | 50 | import org.onosproject.net.provider.ProviderId; |
| 44 | import org.slf4j.Logger; | 51 | import org.slf4j.Logger; |
| 45 | 52 | ||
| 46 | import java.net.URI; | 53 | import java.net.URI; |
| 47 | import java.net.URISyntaxException; | 54 | import java.net.URISyntaxException; |
| 48 | -import java.util.Set; | 55 | +import java.util.List; |
| 56 | +import java.util.concurrent.ConcurrentMap; | ||
| 49 | import java.util.concurrent.ExecutorService; | 57 | import java.util.concurrent.ExecutorService; |
| 50 | import java.util.concurrent.Executors; | 58 | import java.util.concurrent.Executors; |
| 51 | import java.util.concurrent.TimeUnit; | 59 | import java.util.concurrent.TimeUnit; |
| 52 | 60 | ||
| 53 | import static org.onlab.util.Tools.groupedThreads; | 61 | import static org.onlab.util.Tools.groupedThreads; |
| 62 | +import static org.onosproject.bmv2.ctl.Bmv2ThriftClient.forceDisconnectOf; | ||
| 54 | import static org.onosproject.bmv2.ctl.Bmv2ThriftClient.ping; | 63 | import static org.onosproject.bmv2.ctl.Bmv2ThriftClient.ping; |
| 55 | import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY; | 64 | import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY; |
| 56 | import static org.slf4j.LoggerFactory.getLogger; | 65 | import static org.slf4j.LoggerFactory.getLogger; |
| ... | @@ -61,30 +70,14 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -61,30 +70,14 @@ import static org.slf4j.LoggerFactory.getLogger; |
| 61 | @Component(immediate = true) | 70 | @Component(immediate = true) |
| 62 | public class Bmv2DeviceProvider extends AbstractDeviceProvider { | 71 | public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 63 | 72 | ||
| 64 | - private final Logger log = getLogger(Bmv2DeviceProvider.class); | 73 | + private static final Logger LOG = getLogger(Bmv2DeviceProvider.class); |
| 65 | 74 | ||
| 66 | public static final String MANUFACTURER = "p4.org"; | 75 | public static final String MANUFACTURER = "p4.org"; |
| 67 | public static final String HW_VERSION = "bmv2"; | 76 | public static final String HW_VERSION = "bmv2"; |
| 77 | + public static final String SCHEME = "bmv2"; | ||
| 68 | private static final String APP_NAME = "org.onosproject.bmv2"; | 78 | private static final String APP_NAME = "org.onosproject.bmv2"; |
| 69 | private static final String UNKNOWN = "unknown"; | 79 | private static final String UNKNOWN = "unknown"; |
| 70 | - public static final String SCHEME = "bmv2"; | 80 | + private static final int POLL_INTERVAL = 5; // seconds |
| 71 | - | ||
| 72 | - private final ExecutorService deviceDiscoveryExecutor = Executors | ||
| 73 | - .newFixedThreadPool(5, groupedThreads("onos/bmv2", "device-discovery", log)); | ||
| 74 | - | ||
| 75 | - private final NetworkConfigListener cfgListener = new InternalNetworkConfigListener(); | ||
| 76 | - | ||
| 77 | - private final ConfigFactory cfgFactory = | ||
| 78 | - new ConfigFactory<ApplicationId, Bmv2ProviderConfig>( | ||
| 79 | - APP_SUBJECT_FACTORY, Bmv2ProviderConfig.class, | ||
| 80 | - "devices", true) { | ||
| 81 | - @Override | ||
| 82 | - public Bmv2ProviderConfig createConfig() { | ||
| 83 | - return new Bmv2ProviderConfig(); | ||
| 84 | - } | ||
| 85 | - }; | ||
| 86 | - | ||
| 87 | - private final Set<DeviceId> activeDevices = Sets.newConcurrentHashSet(); | ||
| 88 | 81 | ||
| 89 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 82 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 90 | protected NetworkConfigRegistry netCfgService; | 83 | protected NetworkConfigRegistry netCfgService; |
| ... | @@ -95,6 +88,17 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -95,6 +88,17 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 95 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 88 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 96 | protected DeviceService deviceService; | 89 | protected DeviceService deviceService; |
| 97 | 90 | ||
| 91 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 92 | + protected Bmv2ControlPlaneServer controlPlaneServer; | ||
| 93 | + | ||
| 94 | + private final ExecutorService deviceDiscoveryExecutor = Executors | ||
| 95 | + .newFixedThreadPool(5, groupedThreads("onos/bmv2", "device-discovery", LOG)); | ||
| 96 | + | ||
| 97 | + private final NetworkConfigListener cfgListener = new InternalNetworkConfigListener(); | ||
| 98 | + private final ConfigFactory cfgFactory = new InternalConfigFactory(); | ||
| 99 | + private final ConcurrentMap<DeviceId, Boolean> activeDevices = Maps.newConcurrentMap(); | ||
| 100 | + private final DevicePoller devicePoller = new DevicePoller(); | ||
| 101 | + private final InternalHelloListener helloListener = new InternalHelloListener(); | ||
| 98 | private ApplicationId appId; | 102 | private ApplicationId appId; |
| 99 | 103 | ||
| 100 | /** | 104 | /** |
| ... | @@ -104,56 +108,66 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -104,56 +108,66 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 104 | super(new ProviderId("bmv2", "org.onosproject.provider.device")); | 108 | super(new ProviderId("bmv2", "org.onosproject.provider.device")); |
| 105 | } | 109 | } |
| 106 | 110 | ||
| 107 | - protected static DeviceId deviceIdOf(Bmv2ProviderConfig.Bmv2DeviceInfo info) { | 111 | + private static DeviceId deviceIdOf(String ip, int port) { |
| 108 | try { | 112 | try { |
| 109 | - return DeviceId.deviceId(new URI( | 113 | + return DeviceId.deviceId(new URI(SCHEME, ip + ":" + port, null)); |
| 110 | - SCHEME, info.ip().toString() + ":" + info.port(), null)); | ||
| 111 | } catch (URISyntaxException e) { | 114 | } catch (URISyntaxException e) { |
| 112 | - throw new IllegalArgumentException( | 115 | + throw new IllegalArgumentException("Unable to build deviceID for device " + ip + ":" + port, e); |
| 113 | - "Unable to build deviceID for device " | ||
| 114 | - + info.ip().toString() + ":" + info.ip().toString(), | ||
| 115 | - e); | ||
| 116 | } | 116 | } |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | + /** | ||
| 120 | + * Creates a new device ID for the given BMv2 device. | ||
| 121 | + * | ||
| 122 | + * @param device a BMv2 device object | ||
| 123 | + * | ||
| 124 | + * @return a new device ID | ||
| 125 | + */ | ||
| 126 | + public static DeviceId deviceIdOf(Bmv2Device device) { | ||
| 127 | + return deviceIdOf(device.thriftServerHost(), device.thriftServerPort()); | ||
| 128 | + } | ||
| 129 | + | ||
| 119 | @Override | 130 | @Override |
| 120 | protected void activate() { | 131 | protected void activate() { |
| 121 | appId = coreService.registerApplication(APP_NAME); | 132 | appId = coreService.registerApplication(APP_NAME); |
| 122 | netCfgService.registerConfigFactory(cfgFactory); | 133 | netCfgService.registerConfigFactory(cfgFactory); |
| 123 | netCfgService.addListener(cfgListener); | 134 | netCfgService.addListener(cfgListener); |
| 124 | - | 135 | + controlPlaneServer.addHelloListener(helloListener); |
| 136 | + devicePoller.start(); | ||
| 125 | super.activate(); | 137 | super.activate(); |
| 126 | } | 138 | } |
| 127 | 139 | ||
| 128 | @Override | 140 | @Override |
| 129 | protected void deactivate() { | 141 | protected void deactivate() { |
| 142 | + devicePoller.stop(); | ||
| 143 | + controlPlaneServer.removeHelloListener(helloListener); | ||
| 130 | try { | 144 | try { |
| 131 | - activeDevices.stream().forEach(did -> { | 145 | + activeDevices.forEach((did, value) -> { |
| 132 | deviceDiscoveryExecutor.execute(() -> disconnectDevice(did)); | 146 | deviceDiscoveryExecutor.execute(() -> disconnectDevice(did)); |
| 133 | }); | 147 | }); |
| 134 | deviceDiscoveryExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS); | 148 | deviceDiscoveryExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS); |
| 135 | } catch (InterruptedException e) { | 149 | } catch (InterruptedException e) { |
| 136 | - log.error("Device discovery threads did not terminate"); | 150 | + LOG.error("Device discovery threads did not terminate"); |
| 137 | } | 151 | } |
| 138 | deviceDiscoveryExecutor.shutdownNow(); | 152 | deviceDiscoveryExecutor.shutdownNow(); |
| 139 | netCfgService.unregisterConfigFactory(cfgFactory); | 153 | netCfgService.unregisterConfigFactory(cfgFactory); |
| 140 | netCfgService.removeListener(cfgListener); | 154 | netCfgService.removeListener(cfgListener); |
| 141 | - | ||
| 142 | super.deactivate(); | 155 | super.deactivate(); |
| 143 | } | 156 | } |
| 144 | 157 | ||
| 145 | @Override | 158 | @Override |
| 146 | public void triggerProbe(DeviceId deviceId) { | 159 | public void triggerProbe(DeviceId deviceId) { |
| 160 | + // Asynchronously trigger probe task. | ||
| 147 | deviceDiscoveryExecutor.execute(() -> executeProbe(deviceId)); | 161 | deviceDiscoveryExecutor.execute(() -> executeProbe(deviceId)); |
| 148 | } | 162 | } |
| 149 | 163 | ||
| 150 | private void executeProbe(DeviceId did) { | 164 | private void executeProbe(DeviceId did) { |
| 151 | boolean reachable = isReachable(did); | 165 | boolean reachable = isReachable(did); |
| 152 | - log.debug("Probed device: id={}, reachable={}", | 166 | + LOG.debug("Probed device: id={}, reachable={}", |
| 153 | did.toString(), | 167 | did.toString(), |
| 154 | reachable); | 168 | reachable); |
| 155 | if (reachable) { | 169 | if (reachable) { |
| 156 | - connectDevice(did); | 170 | + discoverDevice(did); |
| 157 | } else { | 171 | } else { |
| 158 | disconnectDevice(did); | 172 | disconnectDevice(did); |
| 159 | } | 173 | } |
| ... | @@ -161,7 +175,7 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -161,7 +175,7 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 161 | 175 | ||
| 162 | @Override | 176 | @Override |
| 163 | public void roleChanged(DeviceId deviceId, MastershipRole newRole) { | 177 | public void roleChanged(DeviceId deviceId, MastershipRole newRole) { |
| 164 | - log.debug("roleChanged() is not yet implemented"); | 178 | + LOG.debug("roleChanged() is not yet implemented"); |
| 165 | // TODO: implement mastership handling | 179 | // TODO: implement mastership handling |
| 166 | } | 180 | } |
| 167 | 181 | ||
| ... | @@ -172,41 +186,69 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -172,41 +186,69 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 172 | 186 | ||
| 173 | @Override | 187 | @Override |
| 174 | public void changePortState(DeviceId deviceId, PortNumber portNumber, boolean enable) { | 188 | public void changePortState(DeviceId deviceId, PortNumber portNumber, boolean enable) { |
| 175 | - log.debug("changePortState() is not yet implemented"); | 189 | + LOG.debug("changePortState() is not yet implemented"); |
| 176 | // TODO: implement port handling | 190 | // TODO: implement port handling |
| 177 | } | 191 | } |
| 178 | 192 | ||
| 179 | - private void connectDevice(DeviceId did) { | 193 | + private void discoverDevice(DeviceId did) { |
| 180 | - log.debug("Trying to create device on ONOS core: {}", did); | 194 | + LOG.debug("Starting device discovery... deviceId={}", did); |
| 181 | - SparseAnnotations annotations = DefaultAnnotations.builder() | 195 | + |
| 182 | - .set(AnnotationKeys.PROTOCOL, SCHEME) | 196 | + // Atomically notify device to core and update port information. |
| 183 | - .build(); | 197 | + activeDevices.compute(did, (k, v) -> { |
| 184 | - DeviceDescription descr = new DefaultDeviceDescription( | 198 | + if (!deviceService.isAvailable(did)) { |
| 185 | - did.uri(), Device.Type.SWITCH, MANUFACTURER, HW_VERSION, | 199 | + // Device not available in the core, connect it now. |
| 186 | - UNKNOWN, UNKNOWN, new ChassisId(), annotations); | 200 | + SparseAnnotations annotations = DefaultAnnotations.builder() |
| 187 | - providerService.deviceConnected(did, descr); | 201 | + .set(AnnotationKeys.PROTOCOL, SCHEME) |
| 188 | - activeDevices.add(did); | 202 | + .build(); |
| 189 | - discoverPorts(did); | 203 | + DeviceDescription descr = new DefaultDeviceDescription( |
| 190 | - } | 204 | + did.uri(), Device.Type.SWITCH, MANUFACTURER, HW_VERSION, |
| 191 | - | 205 | + UNKNOWN, UNKNOWN, new ChassisId(), annotations); |
| 192 | - private void discoverPorts(DeviceId did) { | 206 | + providerService.deviceConnected(did, descr); |
| 193 | - Device device = deviceService.getDevice(did); | 207 | + } |
| 194 | - if (device.is(PortDiscovery.class)) { | 208 | + // Discover ports. |
| 195 | - PortDiscovery portConfig = device.as(PortDiscovery.class); | 209 | + Device device = deviceService.getDevice(did); |
| 196 | - providerService.updatePorts(did, portConfig.getPorts()); | 210 | + if (device.is(PortDiscovery.class)) { |
| 197 | - } else { | 211 | + PortDiscovery portConfig = device.as(PortDiscovery.class); |
| 198 | - log.warn("No PortDiscovery behavior for device {}", did); | 212 | + List<PortDescription> portDescriptions = portConfig.getPorts(); |
| 199 | - } | 213 | + providerService.updatePorts(did, portDescriptions); |
| 214 | + } else { | ||
| 215 | + LOG.warn("No PortDiscovery behavior for device {}", did); | ||
| 216 | + } | ||
| 217 | + return true; | ||
| 218 | + }); | ||
| 200 | } | 219 | } |
| 201 | 220 | ||
| 202 | private void disconnectDevice(DeviceId did) { | 221 | private void disconnectDevice(DeviceId did) { |
| 203 | - log.debug("Trying to remove device from ONOS core: {}", did); | 222 | + LOG.debug("Trying to disconnect device from core... deviceId={}", did); |
| 204 | - providerService.deviceDisconnected(did); | 223 | + |
| 205 | - activeDevices.remove(did); | 224 | + // Atomically disconnect device. |
| 225 | + activeDevices.compute(did, (k, v) -> { | ||
| 226 | + if (deviceService.isAvailable(did)) { | ||
| 227 | + providerService.deviceDisconnected(did); | ||
| 228 | + // Make sure to close the transport session with device. | ||
| 229 | + forceDisconnectOf(did); | ||
| 230 | + } | ||
| 231 | + return null; | ||
| 232 | + }); | ||
| 233 | + } | ||
| 234 | + | ||
| 235 | + /** | ||
| 236 | + * Internal net-cfg config factory. | ||
| 237 | + */ | ||
| 238 | + private class InternalConfigFactory extends ConfigFactory<ApplicationId, Bmv2ProviderConfig> { | ||
| 239 | + | ||
| 240 | + InternalConfigFactory() { | ||
| 241 | + super(APP_SUBJECT_FACTORY, Bmv2ProviderConfig.class, "devices", true); | ||
| 242 | + } | ||
| 243 | + | ||
| 244 | + @Override | ||
| 245 | + public Bmv2ProviderConfig createConfig() { | ||
| 246 | + return new Bmv2ProviderConfig(); | ||
| 247 | + } | ||
| 206 | } | 248 | } |
| 207 | 249 | ||
| 208 | /** | 250 | /** |
| 209 | - * Handles net-cfg events. | 251 | + * Internal net-cfg event listener. |
| 210 | */ | 252 | */ |
| 211 | private class InternalNetworkConfigListener implements NetworkConfigListener { | 253 | private class InternalNetworkConfigListener implements NetworkConfigListener { |
| 212 | 254 | ||
| ... | @@ -216,13 +258,13 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -216,13 +258,13 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 216 | if (cfg != null) { | 258 | if (cfg != null) { |
| 217 | try { | 259 | try { |
| 218 | cfg.getDevicesInfo().stream().forEach(info -> { | 260 | cfg.getDevicesInfo().stream().forEach(info -> { |
| 219 | - triggerProbe(deviceIdOf(info)); | 261 | + triggerProbe(deviceIdOf(info.ip().toString(), info.port())); |
| 220 | }); | 262 | }); |
| 221 | } catch (ConfigException e) { | 263 | } catch (ConfigException e) { |
| 222 | - log.error("Unable to read config: " + e); | 264 | + LOG.error("Unable to read config: " + e); |
| 223 | } | 265 | } |
| 224 | } else { | 266 | } else { |
| 225 | - log.error("Unable to read config (was null)"); | 267 | + LOG.error("Unable to read config (was null)"); |
| 226 | } | 268 | } |
| 227 | } | 269 | } |
| 228 | 270 | ||
| ... | @@ -233,4 +275,50 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { | ... | @@ -233,4 +275,50 @@ public class Bmv2DeviceProvider extends AbstractDeviceProvider { |
| 233 | event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED); | 275 | event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED); |
| 234 | } | 276 | } |
| 235 | } | 277 | } |
| 278 | + | ||
| 279 | + /** | ||
| 280 | + * Listener triggered by Bmv2ControlPlaneServer each time a hello message is received. | ||
| 281 | + */ | ||
| 282 | + private class InternalHelloListener implements Bmv2ControlPlaneServer.HelloListener { | ||
| 283 | + @Override | ||
| 284 | + public void handleHello(Bmv2Device device) { | ||
| 285 | + log.debug("Received hello from {}", device); | ||
| 286 | + triggerProbe(deviceIdOf(device)); | ||
| 287 | + } | ||
| 288 | + } | ||
| 289 | + | ||
| 290 | + /** | ||
| 291 | + * Task that periodically trigger device probes. | ||
| 292 | + */ | ||
| 293 | + private class DevicePoller implements TimerTask { | ||
| 294 | + | ||
| 295 | + private final HashedWheelTimer timer = Timer.getTimer(); | ||
| 296 | + private Timeout timeout; | ||
| 297 | + | ||
| 298 | + @Override | ||
| 299 | + public void run(Timeout timeout) throws Exception { | ||
| 300 | + if (timeout.isCancelled()) { | ||
| 301 | + return; | ||
| 302 | + } | ||
| 303 | + log.debug("Executing polling on {} devices...", activeDevices.size()); | ||
| 304 | + activeDevices.forEach((did, value) -> triggerProbe(did)); | ||
| 305 | + timeout.getTimer().newTimeout(this, POLL_INTERVAL, TimeUnit.SECONDS); | ||
| 306 | + } | ||
| 307 | + | ||
| 308 | + /** | ||
| 309 | + * Starts the collector. | ||
| 310 | + */ | ||
| 311 | + synchronized void start() { | ||
| 312 | + LOG.info("Starting device poller..."); | ||
| 313 | + timeout = timer.newTimeout(this, 1, TimeUnit.SECONDS); | ||
| 314 | + } | ||
| 315 | + | ||
| 316 | + /** | ||
| 317 | + * Stops the collector. | ||
| 318 | + */ | ||
| 319 | + synchronized void stop() { | ||
| 320 | + LOG.info("Stopping device poller..."); | ||
| 321 | + timeout.cancel(); | ||
| 322 | + } | ||
| 323 | + } | ||
| 236 | } | 324 | } | ... | ... |
-
Please register or login to post a comment