blob: 4cd809b46d71da3a4808259689886109bbe6c3e4 [file] [log] [blame]
kmcpeakeb172d5f2015-12-10 11:30:43 +00001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.provider.snmp.device.impl;
17
kmcpeakeb172d5f2015-12-10 11:30:43 +000018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Modified;
kmcpeakeb172d5f2015-12-10 11:30:43 +000022import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.onlab.packet.ChassisId;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070025import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
27import org.onosproject.incubator.net.config.basics.ConfigException;
Marc De Leenheerc662d322016-02-18 16:05:10 -080028import org.onosproject.net.AnnotationKeys;
29import org.onosproject.net.DefaultAnnotations;
kmcpeakeb172d5f2015-12-10 11:30:43 +000030import org.onosproject.net.Device;
31import org.onosproject.net.DeviceId;
32import org.onosproject.net.MastershipRole;
Saurav Dasa2d37502016-03-25 17:50:40 -070033import org.onosproject.net.PortNumber;
Marc De Leenheerc662d322016-02-18 16:05:10 -080034import org.onosproject.net.SparseAnnotations;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070035import org.onosproject.net.config.ConfigFactory;
36import org.onosproject.net.config.NetworkConfigEvent;
37import org.onosproject.net.config.NetworkConfigListener;
38import org.onosproject.net.config.NetworkConfigRegistry;
kmcpeakeb172d5f2015-12-10 11:30:43 +000039import org.onosproject.net.device.DefaultDeviceDescription;
40import org.onosproject.net.device.DeviceDescription;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070041import org.onosproject.net.device.DeviceDescriptionDiscovery;
kmcpeakeb172d5f2015-12-10 11:30:43 +000042import org.onosproject.net.device.DeviceProvider;
43import org.onosproject.net.device.DeviceProviderRegistry;
44import org.onosproject.net.device.DeviceProviderService;
45import org.onosproject.net.device.DeviceService;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070046import org.onosproject.net.device.DeviceStore;
kmcpeakeb172d5f2015-12-10 11:30:43 +000047import org.onosproject.net.provider.AbstractProvider;
48import org.onosproject.net.provider.ProviderId;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070049import org.onosproject.snmp.SnmpController;
50import org.onosproject.snmp.SnmpDevice;
51import org.onosproject.snmp.ctl.DefaultSnmpDevice;
kmcpeakeb172d5f2015-12-10 11:30:43 +000052import org.osgi.service.component.ComponentContext;
53import org.slf4j.Logger;
54
Jonathan Hart51539b82015-10-29 09:53:04 -070055import java.util.concurrent.ExecutorService;
56import java.util.concurrent.Executors;
57import java.util.concurrent.TimeUnit;
58
Jonathan Hart51539b82015-10-29 09:53:04 -070059import static org.onlab.util.Tools.groupedThreads;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070060import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Jonathan Hart51539b82015-10-29 09:53:04 -070061import static org.slf4j.LoggerFactory.getLogger;
62
kmcpeakeb172d5f2015-12-10 11:30:43 +000063/**
64 * Provider which will try to fetch the details of SNMP devices from the core and run a capability discovery on each of
65 * the device.
66 */
67@Component(immediate = true)
68public class SnmpDeviceProvider extends AbstractProvider
69 implements DeviceProvider {
70
71 private final Logger log = getLogger(SnmpDeviceProvider.class);
72
73 private static final String UNKNOWN = "unknown";
Andrea Campanellac2d754b2016-03-29 17:51:07 -070074 private static final String APP_NAME = "org.onosproject.snmp";
75 private static final String SCHEME = "snmp";
kmcpeakeb172d5f2015-12-10 11:30:43 +000076
77 private DeviceProviderService providerService;
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070080 protected SnmpController controller;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
kmcpeakeb172d5f2015-12-10 11:30:43 +000083 protected DeviceProviderRegistry providerRegistry;
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected DeviceService deviceService;
87
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070089 protected DeviceStore deviceStore;
kmcpeakeb172d5f2015-12-10 11:30:43 +000090
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070092 protected CoreService coreService;
kmcpeakeb172d5f2015-12-10 11:30:43 +000093
Andrea Campanellac2d754b2016-03-29 17:51:07 -070094 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected NetworkConfigRegistry netCfgService;
kmcpeakeb172d5f2015-12-10 11:30:43 +000096
Andrea Campanellac2d754b2016-03-29 17:51:07 -070097 private final ExecutorService deviceBuilderExecutor = Executors
98 .newFixedThreadPool(5, groupedThreads("onos/snmp", "device-creator", log));
kmcpeakeb172d5f2015-12-10 11:30:43 +000099
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700100 private final NetworkConfigListener cfgLister = new InternalNetworkConfigListener();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000101
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700102 private ApplicationId appId;
kmcpeakeb172d5f2015-12-10 11:30:43 +0000103
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700104 private final ConfigFactory factory =
105 new ConfigFactory<ApplicationId, SnmpProviderConfig>(APP_SUBJECT_FACTORY,
106 SnmpProviderConfig.class,
107 "devices",
108 true) {
109 @Override
110 public SnmpProviderConfig createConfig() {
111 return new SnmpProviderConfig();
112 }
113 };
kmcpeakeb172d5f2015-12-10 11:30:43 +0000114
kmcpeakeb172d5f2015-12-10 11:30:43 +0000115
116 /**
117 * Creates a provider with the supplier identifier.
118 */
119 public SnmpDeviceProvider() {
120 super(new ProviderId("snmp", "org.onosproject.provider.device"));
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700121 //FIXME multiple type of SNMP sessions
kmcpeakeb172d5f2015-12-10 11:30:43 +0000122 }
123
124 @Activate
125 public void activate(ComponentContext context) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700126
kmcpeakeb172d5f2015-12-10 11:30:43 +0000127 providerService = providerRegistry.register(this);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700128 appId = coreService.registerApplication(APP_NAME);
129 netCfgService.registerConfigFactory(factory);
130 netCfgService.addListener(cfgLister);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000131 modified(context);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700132 log.info("Started");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000133 }
134
135 @Deactivate
136 public void deactivate(ComponentContext context) {
137
kmcpeakeb172d5f2015-12-10 11:30:43 +0000138 try {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700139 controller.getDevices().stream().forEach(device -> {
140 deviceBuilderExecutor.execute(new DeviceFactory(device, false));
141 });
142 deviceBuilderExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000143 } catch (InterruptedException e) {
144 log.error("Device builder did not terminate");
145 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700146 deviceBuilderExecutor.shutdownNow();
147 netCfgService.unregisterConfigFactory(factory);
148 netCfgService.removeListener(cfgLister);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000149 providerRegistry.unregister(this);
150 providerService = null;
151 log.info("Stopped");
152 }
153
154 @Modified
155 public void modified(ComponentContext context) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700156 log.info("Modified");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000157 }
158
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700159 private void addOrRemoveDevicesConfig() {
160 SnmpProviderConfig cfg = netCfgService.getConfig(appId, SnmpProviderConfig.class);
161 if (cfg != null) {
kmcpeakeb172d5f2015-12-10 11:30:43 +0000162 try {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700163 cfg.getDevicesInfo().stream().forEach(info -> {
164 SnmpDevice device = new DefaultSnmpDevice(info.ip().toString(),
165 info.port(), info.username(), info.password());
166 buildDevice(device);
167 });
168 } catch (ConfigException e) {
169 log.error("Cannot read config error " + e);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000170 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000171 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700172 }
173
174 private void buildDevice(SnmpDevice device) {
175 if (device != null) {
176 log.debug("Device Detail:host={}, port={}, state={}",
177 device.getSnmpHost(),
178 device.getSnmpPort(),
179 device.isReachable());
180 if (device.isReachable()) {
181 deviceBuilderExecutor.execute(new DeviceFactory(device, true));
182 } else {
183 deviceBuilderExecutor.execute(new DeviceFactory(device, false));
184 }
185 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000186 }
187
188 @Override
189 public void triggerProbe(DeviceId deviceId) {
190 // TODO SNMP devices should be polled at scheduled intervals to retrieve their
191 // reachability status and other details e.g.swVersion, serialNumber,chassis,
192 }
193
194 @Override
195 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700196 // TODO Implement Masterhsip Service
kmcpeakeb172d5f2015-12-10 11:30:43 +0000197 }
198
199 @Override
200 public boolean isReachable(DeviceId deviceId) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700201 SnmpDevice snmpDevice = controller.getDevice(deviceId);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000202 if (snmpDevice == null) {
203 log.warn("BAD REQUEST: the requested device id: "
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700204 + deviceId.toString()
205 + " is not associated to any SNMP Device");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000206 return false;
207 }
208 return snmpDevice.isReachable();
209 }
210
211 /**
212 * This class is intended to add or remove Configured SNMP Devices. Functionality relies on 'createFlag' and
213 * 'SnmpDevice' content. The functionality runs as a thread and depending on the 'createFlag' value it will create
214 * or remove Device entry from the core.
215 */
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700216 //FIXME consider rework.
217 private class DeviceFactory implements Runnable {
kmcpeakeb172d5f2015-12-10 11:30:43 +0000218
219 private SnmpDevice device;
220 private boolean createFlag;
221
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700222 public DeviceFactory(SnmpDevice device, boolean createFlag) {
kmcpeakeb172d5f2015-12-10 11:30:43 +0000223 this.device = device;
224 this.createFlag = createFlag;
225 }
226
227 @Override
228 public void run() {
229 if (createFlag) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700230 log.debug("Trying to create Device Info on ONOS core");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000231 advertiseDevices();
232 } else {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700233 log.debug("Trying to remove Device Info on ONOS core");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000234 removeDevices();
235 }
236 }
237
238 /**
239 * For each SNMP Device, remove the entry from the device store.
240 */
241 private void removeDevices() {
242 if (device == null) {
243 log.warn("The Request SNMP Device is null, cannot proceed further");
244 return;
245 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700246 DeviceId did = device.deviceId();
247 if (controller.getDevice(did) == null) {
248 log.error("BAD Request: 'Currently device is not discovered, "
249 + "so cannot remove/disconnect the device: "
250 + device.deviceInfo() + "'");
251 return;
kmcpeakeb172d5f2015-12-10 11:30:43 +0000252 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700253 providerService.deviceDisconnected(did);
254 device.disconnect();
255 controller.removeDevice(did);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000256 }
257
258 /**
259 * Initialize SNMP Device object, and notify core saying device connected.
260 */
261 private void advertiseDevices() {
262 try {
263 if (device == null) {
264 log.warn("The Request SNMP Device is null, cannot proceed further");
265 return;
266 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700267 DeviceId did = device.deviceId();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000268 ChassisId cid = new ChassisId();
269
Marc De Leenheerc662d322016-02-18 16:05:10 -0800270 SparseAnnotations annotations = DefaultAnnotations.builder()
271 .set(AnnotationKeys.PROTOCOL, SCHEME.toUpperCase())
272 .build();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000273
274 DeviceDescription desc = new DefaultDeviceDescription(
Marc De Leenheerc662d322016-02-18 16:05:10 -0800275 did.uri(), Device.Type.OTHER, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, cid, annotations);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000276
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700277 log.debug("Persisting Device " + did.uri().toString());
kmcpeakeb172d5f2015-12-10 11:30:43 +0000278
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700279 controller.addDevice(did, device);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000280 providerService.deviceConnected(did, desc);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700281 log.info("Added device to ONOS core. Device Info: "
282 + device.deviceInfo() + " " + did.uri().toString());
283 //FIXME this description will be populated only if driver is pushed from outside
284 // becuase otherwise default driver is used
Marc De Leenheerc662d322016-02-18 16:05:10 -0800285 Device d = deviceService.getDevice(did);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700286 if (d.is(DeviceDescriptionDiscovery.class)) {
287 DeviceDescriptionDiscovery descriptionDiscovery = d.as(DeviceDescriptionDiscovery.class);
288 DeviceDescription description = descriptionDiscovery.discoverDeviceDetails();
289 deviceStore.createOrUpdateDevice(
290 new ProviderId("snmp", "org.onosproject.provider.device"),
291 did, description);
292 providerService.updatePorts(did, descriptionDiscovery.discoverPortDetails());
Marc De Leenheerc662d322016-02-18 16:05:10 -0800293 } else {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700294 log.warn("No populate description and ports behaviour for device {}", did);
Marc De Leenheerc662d322016-02-18 16:05:10 -0800295 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000296 } catch (Exception e) {
297 log.error("Error while initializing session for the device: "
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700298 + (device != null ? device.deviceInfo() : null), e);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000299 }
300 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000301 }
302
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700303 private class InternalNetworkConfigListener implements NetworkConfigListener {
304
305
306 @Override
307 public void event(NetworkConfigEvent event) {
308 addOrRemoveDevicesConfig();
309 }
310
311 @Override
312 public boolean isRelevant(NetworkConfigEvent event) {
313 return event.configClass().equals(SnmpProviderConfig.class) &&
314 (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
315 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED);
316 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000317 }
Saurav Dasa2d37502016-03-25 17:50:40 -0700318
319 @Override
320 public void changePortState(DeviceId deviceId, PortNumber portNumber,
321 boolean enable) {
322 // TODO if required
323 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000324}