blob: 2a3695089f1acb3055c39913b2475ba76e83130f [file] [log] [blame]
kmcpeakeb172d5f2015-12-10 11:30:43 +00001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
kmcpeakeb172d5f2015-12-10 11:30:43 +00003 *
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
kmcpeakeb172d5f2015-12-10 11:30:43 +000077 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070078 protected SnmpController controller;
79
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
kmcpeakeb172d5f2015-12-10 11:30:43 +000081 protected DeviceProviderRegistry providerRegistry;
82
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected DeviceService deviceService;
85
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070087 protected DeviceStore deviceStore;
kmcpeakeb172d5f2015-12-10 11:30:43 +000088
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070090 protected CoreService coreService;
kmcpeakeb172d5f2015-12-10 11:30:43 +000091
Andrea Campanellac2d754b2016-03-29 17:51:07 -070092 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected NetworkConfigRegistry netCfgService;
kmcpeakeb172d5f2015-12-10 11:30:43 +000094
Andrea Campanella58454b92016-04-01 15:19:00 -070095 protected DeviceProviderService providerService;
96
97 protected ApplicationId appId;
98
Andrea Campanellac2d754b2016-03-29 17:51:07 -070099 private final ExecutorService deviceBuilderExecutor = Executors
100 .newFixedThreadPool(5, groupedThreads("onos/snmp", "device-creator", log));
kmcpeakeb172d5f2015-12-10 11:30:43 +0000101
Andrea Campanella58454b92016-04-01 15:19:00 -0700102 protected final NetworkConfigListener cfgLister = new InternalNetworkConfigListener();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000103
kmcpeakeb172d5f2015-12-10 11:30:43 +0000104
Andrea Campanella58454b92016-04-01 15:19:00 -0700105 protected final ConfigFactory factory =
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700106 new ConfigFactory<ApplicationId, SnmpProviderConfig>(APP_SUBJECT_FACTORY,
107 SnmpProviderConfig.class,
108 "devices",
109 true) {
110 @Override
111 public SnmpProviderConfig createConfig() {
112 return new SnmpProviderConfig();
113 }
114 };
kmcpeakeb172d5f2015-12-10 11:30:43 +0000115
kmcpeakeb172d5f2015-12-10 11:30:43 +0000116
117 /**
118 * Creates a provider with the supplier identifier.
119 */
120 public SnmpDeviceProvider() {
121 super(new ProviderId("snmp", "org.onosproject.provider.device"));
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700122 //FIXME multiple type of SNMP sessions
kmcpeakeb172d5f2015-12-10 11:30:43 +0000123 }
124
125 @Activate
126 public void activate(ComponentContext context) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700127
kmcpeakeb172d5f2015-12-10 11:30:43 +0000128 providerService = providerRegistry.register(this);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700129 appId = coreService.registerApplication(APP_NAME);
130 netCfgService.registerConfigFactory(factory);
131 netCfgService.addListener(cfgLister);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000132 modified(context);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700133 log.info("Started");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000134 }
135
136 @Deactivate
137 public void deactivate(ComponentContext context) {
138
kmcpeakeb172d5f2015-12-10 11:30:43 +0000139 try {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700140 controller.getDevices().forEach(device -> {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700141 deviceBuilderExecutor.execute(new DeviceFactory(device, false));
142 });
143 deviceBuilderExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000144 } catch (InterruptedException e) {
145 log.error("Device builder did not terminate");
146 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700147 deviceBuilderExecutor.shutdownNow();
148 netCfgService.unregisterConfigFactory(factory);
149 netCfgService.removeListener(cfgLister);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000150 providerRegistry.unregister(this);
151 providerService = null;
152 log.info("Stopped");
153 }
154
155 @Modified
156 public void modified(ComponentContext context) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700157 log.info("Modified");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000158 }
159
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700160 private void addOrRemoveDevicesConfig() {
161 SnmpProviderConfig cfg = netCfgService.getConfig(appId, SnmpProviderConfig.class);
162 if (cfg != null) {
kmcpeakeb172d5f2015-12-10 11:30:43 +0000163 try {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700164 cfg.getDevicesInfo().forEach(info -> {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700165 SnmpDevice device = new DefaultSnmpDevice(info.ip().toString(),
166 info.port(), info.username(), info.password());
167 buildDevice(device);
168 });
169 } catch (ConfigException e) {
170 log.error("Cannot read config error " + e);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000171 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000172 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700173 }
174
175 private void buildDevice(SnmpDevice device) {
176 if (device != null) {
177 log.debug("Device Detail:host={}, port={}, state={}",
178 device.getSnmpHost(),
179 device.getSnmpPort(),
180 device.isReachable());
181 if (device.isReachable()) {
182 deviceBuilderExecutor.execute(new DeviceFactory(device, true));
183 } else {
184 deviceBuilderExecutor.execute(new DeviceFactory(device, false));
185 }
186 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000187 }
188
189 @Override
190 public void triggerProbe(DeviceId deviceId) {
191 // TODO SNMP devices should be polled at scheduled intervals to retrieve their
192 // reachability status and other details e.g.swVersion, serialNumber,chassis,
193 }
194
195 @Override
196 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700197 // TODO Implement Masterhsip Service
kmcpeakeb172d5f2015-12-10 11:30:43 +0000198 }
199
200 @Override
201 public boolean isReachable(DeviceId deviceId) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700202 SnmpDevice snmpDevice = controller.getDevice(deviceId);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000203 if (snmpDevice == null) {
204 log.warn("BAD REQUEST: the requested device id: "
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700205 + deviceId.toString()
206 + " is not associated to any SNMP Device");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000207 return false;
208 }
209 return snmpDevice.isReachable();
210 }
211
212 /**
213 * This class is intended to add or remove Configured SNMP Devices. Functionality relies on 'createFlag' and
214 * 'SnmpDevice' content. The functionality runs as a thread and depending on the 'createFlag' value it will create
215 * or remove Device entry from the core.
216 */
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700217 //FIXME consider rework.
218 private class DeviceFactory implements Runnable {
kmcpeakeb172d5f2015-12-10 11:30:43 +0000219
220 private SnmpDevice device;
221 private boolean createFlag;
222
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700223 public DeviceFactory(SnmpDevice device, boolean createFlag) {
kmcpeakeb172d5f2015-12-10 11:30:43 +0000224 this.device = device;
225 this.createFlag = createFlag;
226 }
227
228 @Override
229 public void run() {
230 if (createFlag) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700231 log.debug("Trying to create Device Info on ONOS core");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000232 advertiseDevices();
233 } else {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700234 log.debug("Trying to remove Device Info on ONOS core");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000235 removeDevices();
236 }
237 }
238
239 /**
240 * For each SNMP Device, remove the entry from the device store.
241 */
242 private void removeDevices() {
243 if (device == null) {
244 log.warn("The Request SNMP Device is null, cannot proceed further");
245 return;
246 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700247 DeviceId did = device.deviceId();
248 if (controller.getDevice(did) == null) {
249 log.error("BAD Request: 'Currently device is not discovered, "
250 + "so cannot remove/disconnect the device: "
251 + device.deviceInfo() + "'");
252 return;
kmcpeakeb172d5f2015-12-10 11:30:43 +0000253 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700254 providerService.deviceDisconnected(did);
255 device.disconnect();
256 controller.removeDevice(did);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000257 }
258
259 /**
260 * Initialize SNMP Device object, and notify core saying device connected.
261 */
262 private void advertiseDevices() {
263 try {
264 if (device == null) {
265 log.warn("The Request SNMP Device is null, cannot proceed further");
266 return;
267 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700268 DeviceId did = device.deviceId();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000269 ChassisId cid = new ChassisId();
270
Marc De Leenheerc662d322016-02-18 16:05:10 -0800271 SparseAnnotations annotations = DefaultAnnotations.builder()
272 .set(AnnotationKeys.PROTOCOL, SCHEME.toUpperCase())
273 .build();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000274
275 DeviceDescription desc = new DefaultDeviceDescription(
Marc De Leenheerc662d322016-02-18 16:05:10 -0800276 did.uri(), Device.Type.OTHER, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, cid, annotations);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000277
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700278 log.debug("Persisting Device " + did.uri().toString());
kmcpeakeb172d5f2015-12-10 11:30:43 +0000279
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700280 controller.addDevice(did, device);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000281 providerService.deviceConnected(did, desc);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700282 log.info("Added device to ONOS core. Device Info: "
283 + device.deviceInfo() + " " + did.uri().toString());
284 //FIXME this description will be populated only if driver is pushed from outside
285 // becuase otherwise default driver is used
Marc De Leenheerc662d322016-02-18 16:05:10 -0800286 Device d = deviceService.getDevice(did);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700287 if (d.is(DeviceDescriptionDiscovery.class)) {
288 DeviceDescriptionDiscovery descriptionDiscovery = d.as(DeviceDescriptionDiscovery.class);
289 DeviceDescription description = descriptionDiscovery.discoverDeviceDetails();
Andrea Campanella6c71a052016-04-22 11:56:31 -0700290 if (description != null) {
291 deviceStore.createOrUpdateDevice(
292 new ProviderId("snmp", "org.onosproject.provider.device"),
293 did, description);
294 } else {
295 log.info("No other description given for device {}", d.id());
296 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700297 providerService.updatePorts(did, descriptionDiscovery.discoverPortDetails());
Marc De Leenheerc662d322016-02-18 16:05:10 -0800298 } else {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700299 log.warn("No populate description and ports behaviour for device {}", did);
Marc De Leenheerc662d322016-02-18 16:05:10 -0800300 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000301 } catch (Exception e) {
302 log.error("Error while initializing session for the device: "
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700303 + (device != null ? device.deviceInfo() : null), e);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000304 }
305 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000306 }
307
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700308 private class InternalNetworkConfigListener implements NetworkConfigListener {
309
310
311 @Override
312 public void event(NetworkConfigEvent event) {
313 addOrRemoveDevicesConfig();
314 }
315
316 @Override
317 public boolean isRelevant(NetworkConfigEvent event) {
318 return event.configClass().equals(SnmpProviderConfig.class) &&
319 (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
320 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED);
321 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000322 }
Saurav Dasa2d37502016-03-25 17:50:40 -0700323
324 @Override
325 public void changePortState(DeviceId deviceId, PortNumber portNumber,
326 boolean enable) {
327 // TODO if required
328 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000329}