blob: ddd81c7bba6744f693366989f6215de8d7b53391 [file] [log] [blame]
kmcpeakeb172d5f2015-12-10 11:30:43 +00001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
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
Ray Milkeyd84f89b2018-08-17 14:54:17 -070018import org.osgi.service.component.annotations.Activate;
19import org.osgi.service.component.annotations.Component;
20import org.osgi.service.component.annotations.Deactivate;
21import org.osgi.service.component.annotations.Modified;
22import org.osgi.service.component.annotations.Reference;
23import org.osgi.service.component.annotations.ReferenceCardinality;
kmcpeakeb172d5f2015-12-10 11:30:43 +000024import org.onlab.packet.ChassisId;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070025import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
Marc De Leenheerc662d322016-02-18 16:05:10 -080027import org.onosproject.net.AnnotationKeys;
28import org.onosproject.net.DefaultAnnotations;
kmcpeakeb172d5f2015-12-10 11:30:43 +000029import org.onosproject.net.Device;
30import org.onosproject.net.DeviceId;
31import org.onosproject.net.MastershipRole;
Saurav Dasa2d37502016-03-25 17:50:40 -070032import org.onosproject.net.PortNumber;
Marc De Leenheerc662d322016-02-18 16:05:10 -080033import org.onosproject.net.SparseAnnotations;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070034import org.onosproject.net.config.ConfigFactory;
35import org.onosproject.net.config.NetworkConfigEvent;
36import org.onosproject.net.config.NetworkConfigListener;
37import org.onosproject.net.config.NetworkConfigRegistry;
Andrea Campanella59b549d2017-04-14 21:58:16 +020038import org.onosproject.net.config.basics.SubjectFactories;
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;
Laszlo Papp9655b182017-01-31 13:01:45 -080051import org.onosproject.snmp.SnmpDeviceConfig;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070052import org.onosproject.snmp.ctl.DefaultSnmpDevice;
kmcpeakeb172d5f2015-12-10 11:30:43 +000053import org.osgi.service.component.ComponentContext;
54import org.slf4j.Logger;
55
Andrea Campanella59b549d2017-04-14 21:58:16 +020056import java.util.Set;
Jonathan Hart51539b82015-10-29 09:53:04 -070057import java.util.concurrent.ExecutorService;
58import java.util.concurrent.Executors;
59import java.util.concurrent.TimeUnit;
60
Jonathan Hart51539b82015-10-29 09:53:04 -070061import static org.onlab.util.Tools.groupedThreads;
62import static org.slf4j.LoggerFactory.getLogger;
63
kmcpeakeb172d5f2015-12-10 11:30:43 +000064/**
65 * Provider which will try to fetch the details of SNMP devices from the core and run a capability discovery on each of
66 * the device.
67 */
68@Component(immediate = true)
69public class SnmpDeviceProvider extends AbstractProvider
70 implements DeviceProvider {
71
72 private final Logger log = getLogger(SnmpDeviceProvider.class);
73
74 private static final String UNKNOWN = "unknown";
Andrea Campanellac2d754b2016-03-29 17:51:07 -070075 private static final String APP_NAME = "org.onosproject.snmp";
Andrea Campanella59b549d2017-04-14 21:58:16 +020076 protected static final String SCHEME = "snmp";
kmcpeakeb172d5f2015-12-10 11:30:43 +000077
Ray Milkeyd84f89b2018-08-17 14:54:17 -070078 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070079 protected SnmpController controller;
80
Ray Milkeyd84f89b2018-08-17 14:54:17 -070081 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kmcpeakeb172d5f2015-12-10 11:30:43 +000082 protected DeviceProviderRegistry providerRegistry;
83
Ray Milkeyd84f89b2018-08-17 14:54:17 -070084 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kmcpeakeb172d5f2015-12-10 11:30:43 +000085 protected DeviceService deviceService;
86
Ray Milkeyd84f89b2018-08-17 14:54:17 -070087 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070088 protected DeviceStore deviceStore;
kmcpeakeb172d5f2015-12-10 11:30:43 +000089
Ray Milkeyd84f89b2018-08-17 14:54:17 -070090 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070091 protected CoreService coreService;
kmcpeakeb172d5f2015-12-10 11:30:43 +000092
Ray Milkeyd84f89b2018-08-17 14:54:17 -070093 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070094 protected NetworkConfigRegistry netCfgService;
kmcpeakeb172d5f2015-12-10 11:30:43 +000095
Andrea Campanella58454b92016-04-01 15:19:00 -070096 protected DeviceProviderService providerService;
97
98 protected ApplicationId appId;
99
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700100 private final ExecutorService deviceBuilderExecutor = Executors
101 .newFixedThreadPool(5, groupedThreads("onos/snmp", "device-creator", log));
kmcpeakeb172d5f2015-12-10 11:30:43 +0000102
Andrea Campanella58454b92016-04-01 15:19:00 -0700103 protected final NetworkConfigListener cfgLister = new InternalNetworkConfigListener();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000104
kmcpeakeb172d5f2015-12-10 11:30:43 +0000105
Ray Milkey4ad4a242018-02-13 13:54:40 -0800106 protected final ConfigFactory factory =
Andrea Campanella59b549d2017-04-14 21:58:16 +0200107 new ConfigFactory<DeviceId, SnmpDeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
108 SnmpDeviceConfig.class,
109 SCHEME) {
110 @Override
111 public SnmpDeviceConfig createConfig() {
112 return new SnmpDeviceConfig();
113 }
Ray Milkey4ad4a242018-02-13 13:54:40 -0800114 };
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);
Ray Milkey4ad4a242018-02-13 13:54:40 -0800130 netCfgService.registerConfigFactory(factory);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700131 netCfgService.addListener(cfgLister);
Andrea Campanella59b549d2017-04-14 21:58:16 +0200132 connectDevices();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000133 modified(context);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700134 log.info("Started");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000135 }
136
137 @Deactivate
138 public void deactivate(ComponentContext context) {
139
kmcpeakeb172d5f2015-12-10 11:30:43 +0000140 try {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700141 controller.getDevices().forEach(device -> {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700142 deviceBuilderExecutor.execute(new DeviceFactory(device, false));
143 });
144 deviceBuilderExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000145 } catch (InterruptedException e) {
Ray Milkey5c7d4882018-02-05 14:50:39 -0800146 Thread.currentThread().interrupt();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000147 log.error("Device builder did not terminate");
148 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700149 deviceBuilderExecutor.shutdownNow();
Ray Milkey4ad4a242018-02-13 13:54:40 -0800150 netCfgService.unregisterConfigFactory(factory);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700151 netCfgService.removeListener(cfgLister);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000152 providerRegistry.unregister(this);
153 providerService = null;
154 log.info("Stopped");
155 }
156
157 @Modified
158 public void modified(ComponentContext context) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700159 log.info("Modified");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000160 }
161
Andrea Campanella59b549d2017-04-14 21:58:16 +0200162 //Method to register devices provided via net-cfg under devices/ tree
163 private void connectDevices() {
164 Set<DeviceId> deviceSubjects =
165 netCfgService.getSubjects(DeviceId.class, SnmpDeviceConfig.class);
166 deviceSubjects.forEach(deviceId -> {
167 SnmpDeviceConfig config =
168 netCfgService.getConfig(deviceId, SnmpDeviceConfig.class);
Laszlo Papp9655b182017-01-31 13:01:45 -0800169 buildDevice(new DefaultSnmpDevice(config));
Andrea Campanella59b549d2017-04-14 21:58:16 +0200170 });
171 }
172
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700173 private void buildDevice(SnmpDevice device) {
174 if (device != null) {
175 log.debug("Device Detail:host={}, port={}, state={}",
176 device.getSnmpHost(),
177 device.getSnmpPort(),
178 device.isReachable());
179 if (device.isReachable()) {
180 deviceBuilderExecutor.execute(new DeviceFactory(device, true));
181 } else {
182 deviceBuilderExecutor.execute(new DeviceFactory(device, false));
183 }
184 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000185 }
186
187 @Override
188 public void triggerProbe(DeviceId deviceId) {
189 // TODO SNMP devices should be polled at scheduled intervals to retrieve their
190 // reachability status and other details e.g.swVersion, serialNumber,chassis,
191 }
192
193 @Override
194 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700195 // TODO Implement Masterhsip Service
kmcpeakeb172d5f2015-12-10 11:30:43 +0000196 }
197
198 @Override
199 public boolean isReachable(DeviceId deviceId) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700200 SnmpDevice snmpDevice = controller.getDevice(deviceId);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000201 if (snmpDevice == null) {
202 log.warn("BAD REQUEST: the requested device id: "
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700203 + deviceId.toString()
204 + " is not associated to any SNMP Device");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000205 return false;
206 }
207 return snmpDevice.isReachable();
208 }
209
210 /**
211 * This class is intended to add or remove Configured SNMP Devices. Functionality relies on 'createFlag' and
212 * 'SnmpDevice' content. The functionality runs as a thread and depending on the 'createFlag' value it will create
213 * or remove Device entry from the core.
214 */
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700215 //FIXME consider rework.
216 private class DeviceFactory implements Runnable {
kmcpeakeb172d5f2015-12-10 11:30:43 +0000217
218 private SnmpDevice device;
219 private boolean createFlag;
220
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700221 public DeviceFactory(SnmpDevice device, boolean createFlag) {
kmcpeakeb172d5f2015-12-10 11:30:43 +0000222 this.device = device;
223 this.createFlag = createFlag;
224 }
225
226 @Override
227 public void run() {
228 if (createFlag) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700229 log.debug("Trying to create Device Info on ONOS core");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000230 advertiseDevices();
231 } else {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700232 log.debug("Trying to remove Device Info on ONOS core");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000233 removeDevices();
234 }
235 }
236
237 /**
238 * For each SNMP Device, remove the entry from the device store.
239 */
240 private void removeDevices() {
241 if (device == null) {
242 log.warn("The Request SNMP Device is null, cannot proceed further");
243 return;
244 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700245 DeviceId did = device.deviceId();
246 if (controller.getDevice(did) == null) {
247 log.error("BAD Request: 'Currently device is not discovered, "
248 + "so cannot remove/disconnect the device: "
249 + device.deviceInfo() + "'");
250 return;
kmcpeakeb172d5f2015-12-10 11:30:43 +0000251 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700252 providerService.deviceDisconnected(did);
253 device.disconnect();
254 controller.removeDevice(did);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000255 }
256
257 /**
258 * Initialize SNMP Device object, and notify core saying device connected.
259 */
260 private void advertiseDevices() {
261 try {
262 if (device == null) {
263 log.warn("The Request SNMP Device is null, cannot proceed further");
264 return;
265 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700266 DeviceId did = device.deviceId();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000267 ChassisId cid = new ChassisId();
268
Marc De Leenheerc662d322016-02-18 16:05:10 -0800269 SparseAnnotations annotations = DefaultAnnotations.builder()
270 .set(AnnotationKeys.PROTOCOL, SCHEME.toUpperCase())
271 .build();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000272
273 DeviceDescription desc = new DefaultDeviceDescription(
Marc De Leenheerc662d322016-02-18 16:05:10 -0800274 did.uri(), Device.Type.OTHER, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, cid, annotations);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000275
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700276 log.debug("Persisting Device " + did.uri().toString());
kmcpeakeb172d5f2015-12-10 11:30:43 +0000277
Ray Milkey6b1acfc2018-09-05 16:59:17 -0700278 controller.addDevice(device);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000279 providerService.deviceConnected(did, desc);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700280 log.info("Added device to ONOS core. Device Info: "
281 + device.deviceInfo() + " " + did.uri().toString());
282 //FIXME this description will be populated only if driver is pushed from outside
Frank Wangd8ab0962017-08-11 11:09:30 +0800283 // because otherwise default driver is used
Marc De Leenheerc662d322016-02-18 16:05:10 -0800284 Device d = deviceService.getDevice(did);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700285 if (d.is(DeviceDescriptionDiscovery.class)) {
286 DeviceDescriptionDiscovery descriptionDiscovery = d.as(DeviceDescriptionDiscovery.class);
287 DeviceDescription description = descriptionDiscovery.discoverDeviceDetails();
Andrea Campanella6c71a052016-04-22 11:56:31 -0700288 if (description != null) {
289 deviceStore.createOrUpdateDevice(
290 new ProviderId("snmp", "org.onosproject.provider.device"),
291 did, description);
292 } else {
293 log.info("No other description given for device {}", d.id());
294 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700295 providerService.updatePorts(did, descriptionDiscovery.discoverPortDetails());
Marc De Leenheerc662d322016-02-18 16:05:10 -0800296 } else {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700297 log.warn("No populate description and ports behaviour for device {}", did);
Marc De Leenheerc662d322016-02-18 16:05:10 -0800298 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000299 } catch (Exception e) {
300 log.error("Error while initializing session for the device: "
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700301 + (device != null ? device.deviceInfo() : null), e);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000302 }
303 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000304 }
305
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700306 private class InternalNetworkConfigListener implements NetworkConfigListener {
307
308
309 @Override
310 public void event(NetworkConfigEvent event) {
Andrea Campanella59b549d2017-04-14 21:58:16 +0200311 if (event.configClass().equals(SnmpDeviceConfig.class)) {
312 connectDevices();
313 } else {
314 log.warn("Injecting device via this Json is deprecated, " +
315 "please put configuration under devices/");
Andrea Campanella59b549d2017-04-14 21:58:16 +0200316 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700317 }
318
319 @Override
320 public boolean isRelevant(NetworkConfigEvent event) {
Ray Milkey4ad4a242018-02-13 13:54:40 -0800321 return (event.configClass().equals(SnmpDeviceConfig.class)) &&
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700322 (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
323 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED);
324 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000325 }
Saurav Dasa2d37502016-03-25 17:50:40 -0700326
327 @Override
328 public void changePortState(DeviceId deviceId, PortNumber portNumber,
329 boolean enable) {
330 // TODO if required
331 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000332}