blob: 6a06a98644b24dc08cd2a8b03b2570f7e019100f [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
senthil9d33aa22021-10-05 09:59:32 +053018import org.onosproject.snmp.SnmpException;
19import org.onosproject.snmp.ctl.DefaultSnmpv3Device;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070020import org.osgi.service.component.annotations.Activate;
21import org.osgi.service.component.annotations.Component;
22import org.osgi.service.component.annotations.Deactivate;
23import org.osgi.service.component.annotations.Modified;
24import org.osgi.service.component.annotations.Reference;
25import org.osgi.service.component.annotations.ReferenceCardinality;
kmcpeakeb172d5f2015-12-10 11:30:43 +000026import org.onlab.packet.ChassisId;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070027import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
Marc De Leenheerc662d322016-02-18 16:05:10 -080029import org.onosproject.net.AnnotationKeys;
30import org.onosproject.net.DefaultAnnotations;
kmcpeakeb172d5f2015-12-10 11:30:43 +000031import org.onosproject.net.Device;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.MastershipRole;
Saurav Dasa2d37502016-03-25 17:50:40 -070034import org.onosproject.net.PortNumber;
Marc De Leenheerc662d322016-02-18 16:05:10 -080035import org.onosproject.net.SparseAnnotations;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070036import org.onosproject.net.config.ConfigFactory;
37import org.onosproject.net.config.NetworkConfigEvent;
38import org.onosproject.net.config.NetworkConfigListener;
39import org.onosproject.net.config.NetworkConfigRegistry;
Andrea Campanella59b549d2017-04-14 21:58:16 +020040import org.onosproject.net.config.basics.SubjectFactories;
kmcpeakeb172d5f2015-12-10 11:30:43 +000041import org.onosproject.net.device.DefaultDeviceDescription;
42import org.onosproject.net.device.DeviceDescription;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070043import org.onosproject.net.device.DeviceDescriptionDiscovery;
kmcpeakeb172d5f2015-12-10 11:30:43 +000044import org.onosproject.net.device.DeviceProvider;
45import org.onosproject.net.device.DeviceProviderRegistry;
46import org.onosproject.net.device.DeviceProviderService;
47import org.onosproject.net.device.DeviceService;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070048import org.onosproject.net.device.DeviceStore;
kmcpeakeb172d5f2015-12-10 11:30:43 +000049import org.onosproject.net.provider.AbstractProvider;
50import org.onosproject.net.provider.ProviderId;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070051import org.onosproject.snmp.SnmpController;
52import org.onosproject.snmp.SnmpDevice;
Laszlo Papp9655b182017-01-31 13:01:45 -080053import org.onosproject.snmp.SnmpDeviceConfig;
Andrea Campanellac2d754b2016-03-29 17:51:07 -070054import org.onosproject.snmp.ctl.DefaultSnmpDevice;
kmcpeakeb172d5f2015-12-10 11:30:43 +000055import org.osgi.service.component.ComponentContext;
56import org.slf4j.Logger;
senthil9d33aa22021-10-05 09:59:32 +053057import org.snmp4j.mp.SnmpConstants;
kmcpeakeb172d5f2015-12-10 11:30:43 +000058
Andrea Campanella59b549d2017-04-14 21:58:16 +020059import java.util.Set;
Jonathan Hart51539b82015-10-29 09:53:04 -070060import java.util.concurrent.ExecutorService;
61import java.util.concurrent.Executors;
62import java.util.concurrent.TimeUnit;
63
Jonathan Hart51539b82015-10-29 09:53:04 -070064import static org.onlab.util.Tools.groupedThreads;
65import static org.slf4j.LoggerFactory.getLogger;
66
kmcpeakeb172d5f2015-12-10 11:30:43 +000067/**
68 * Provider which will try to fetch the details of SNMP devices from the core and run a capability discovery on each of
69 * the device.
70 */
71@Component(immediate = true)
72public class SnmpDeviceProvider extends AbstractProvider
73 implements DeviceProvider {
74
75 private final Logger log = getLogger(SnmpDeviceProvider.class);
76
77 private static final String UNKNOWN = "unknown";
Andrea Campanellac2d754b2016-03-29 17:51:07 -070078 private static final String APP_NAME = "org.onosproject.snmp";
Andrea Campanella59b549d2017-04-14 21:58:16 +020079 protected static final String SCHEME = "snmp";
kmcpeakeb172d5f2015-12-10 11:30:43 +000080
Ray Milkeyd84f89b2018-08-17 14:54:17 -070081 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070082 protected SnmpController controller;
83
Ray Milkeyd84f89b2018-08-17 14:54:17 -070084 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kmcpeakeb172d5f2015-12-10 11:30:43 +000085 protected DeviceProviderRegistry providerRegistry;
86
Ray Milkeyd84f89b2018-08-17 14:54:17 -070087 @Reference(cardinality = ReferenceCardinality.MANDATORY)
kmcpeakeb172d5f2015-12-10 11:30:43 +000088 protected DeviceService deviceService;
89
Ray Milkeyd84f89b2018-08-17 14:54:17 -070090 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070091 protected DeviceStore deviceStore;
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 CoreService coreService;
kmcpeakeb172d5f2015-12-10 11:30:43 +000095
Ray Milkeyd84f89b2018-08-17 14:54:17 -070096 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Andrea Campanellac2d754b2016-03-29 17:51:07 -070097 protected NetworkConfigRegistry netCfgService;
kmcpeakeb172d5f2015-12-10 11:30:43 +000098
Andrea Campanella58454b92016-04-01 15:19:00 -070099 protected DeviceProviderService providerService;
100
101 protected ApplicationId appId;
102
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700103 private final ExecutorService deviceBuilderExecutor = Executors
104 .newFixedThreadPool(5, groupedThreads("onos/snmp", "device-creator", log));
kmcpeakeb172d5f2015-12-10 11:30:43 +0000105
Andrea Campanella58454b92016-04-01 15:19:00 -0700106 protected final NetworkConfigListener cfgLister = new InternalNetworkConfigListener();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000107
kmcpeakeb172d5f2015-12-10 11:30:43 +0000108
Ray Milkey4ad4a242018-02-13 13:54:40 -0800109 protected final ConfigFactory factory =
Andrea Campanella59b549d2017-04-14 21:58:16 +0200110 new ConfigFactory<DeviceId, SnmpDeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
111 SnmpDeviceConfig.class,
112 SCHEME) {
113 @Override
114 public SnmpDeviceConfig createConfig() {
115 return new SnmpDeviceConfig();
116 }
Ray Milkey4ad4a242018-02-13 13:54:40 -0800117 };
kmcpeakeb172d5f2015-12-10 11:30:43 +0000118
kmcpeakeb172d5f2015-12-10 11:30:43 +0000119
120 /**
121 * Creates a provider with the supplier identifier.
122 */
123 public SnmpDeviceProvider() {
124 super(new ProviderId("snmp", "org.onosproject.provider.device"));
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700125 //FIXME multiple type of SNMP sessions
kmcpeakeb172d5f2015-12-10 11:30:43 +0000126 }
127
128 @Activate
129 public void activate(ComponentContext context) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700130
kmcpeakeb172d5f2015-12-10 11:30:43 +0000131 providerService = providerRegistry.register(this);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700132 appId = coreService.registerApplication(APP_NAME);
Ray Milkey4ad4a242018-02-13 13:54:40 -0800133 netCfgService.registerConfigFactory(factory);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700134 netCfgService.addListener(cfgLister);
Andrea Campanella59b549d2017-04-14 21:58:16 +0200135 connectDevices();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000136 modified(context);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700137 log.info("Started");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000138 }
139
140 @Deactivate
141 public void deactivate(ComponentContext context) {
142
kmcpeakeb172d5f2015-12-10 11:30:43 +0000143 try {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700144 controller.getDevices().forEach(device -> {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700145 deviceBuilderExecutor.execute(new DeviceFactory(device, false));
146 });
147 deviceBuilderExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000148 } catch (InterruptedException e) {
Ray Milkey5c7d4882018-02-05 14:50:39 -0800149 Thread.currentThread().interrupt();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000150 log.error("Device builder did not terminate");
151 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700152 deviceBuilderExecutor.shutdownNow();
Ray Milkey4ad4a242018-02-13 13:54:40 -0800153 netCfgService.unregisterConfigFactory(factory);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700154 netCfgService.removeListener(cfgLister);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000155 providerRegistry.unregister(this);
156 providerService = null;
157 log.info("Stopped");
158 }
159
160 @Modified
161 public void modified(ComponentContext context) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700162 log.info("Modified");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000163 }
164
Andrea Campanella59b549d2017-04-14 21:58:16 +0200165 //Method to register devices provided via net-cfg under devices/ tree
166 private void connectDevices() {
167 Set<DeviceId> deviceSubjects =
168 netCfgService.getSubjects(DeviceId.class, SnmpDeviceConfig.class);
169 deviceSubjects.forEach(deviceId -> {
170 SnmpDeviceConfig config =
171 netCfgService.getConfig(deviceId, SnmpDeviceConfig.class);
senthil9d33aa22021-10-05 09:59:32 +0530172 if (config.version() == SnmpConstants.version2c) {
173 buildDevice(new DefaultSnmpDevice(config));
174 } else if (config.version() == SnmpConstants.version3) {
175 buildDevice(new DefaultSnmpv3Device(config));
176 } else {
177 throw new SnmpException(
178 String.format("Invalid snmp version %d", config.version()));
179 }
Andrea Campanella59b549d2017-04-14 21:58:16 +0200180 });
181 }
182
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700183 private void buildDevice(SnmpDevice device) {
184 if (device != null) {
185 log.debug("Device Detail:host={}, port={}, state={}",
186 device.getSnmpHost(),
187 device.getSnmpPort(),
188 device.isReachable());
189 if (device.isReachable()) {
190 deviceBuilderExecutor.execute(new DeviceFactory(device, true));
191 } else {
192 deviceBuilderExecutor.execute(new DeviceFactory(device, false));
193 }
194 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000195 }
196
197 @Override
198 public void triggerProbe(DeviceId deviceId) {
199 // TODO SNMP devices should be polled at scheduled intervals to retrieve their
200 // reachability status and other details e.g.swVersion, serialNumber,chassis,
201 }
202
203 @Override
204 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700205 // TODO Implement Masterhsip Service
kmcpeakeb172d5f2015-12-10 11:30:43 +0000206 }
207
208 @Override
209 public boolean isReachable(DeviceId deviceId) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700210 SnmpDevice snmpDevice = controller.getDevice(deviceId);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000211 if (snmpDevice == null) {
212 log.warn("BAD REQUEST: the requested device id: "
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700213 + deviceId.toString()
214 + " is not associated to any SNMP Device");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000215 return false;
216 }
217 return snmpDevice.isReachable();
218 }
219
220 /**
221 * This class is intended to add or remove Configured SNMP Devices. Functionality relies on 'createFlag' and
222 * 'SnmpDevice' content. The functionality runs as a thread and depending on the 'createFlag' value it will create
223 * or remove Device entry from the core.
224 */
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700225 //FIXME consider rework.
226 private class DeviceFactory implements Runnable {
kmcpeakeb172d5f2015-12-10 11:30:43 +0000227
228 private SnmpDevice device;
229 private boolean createFlag;
230
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700231 public DeviceFactory(SnmpDevice device, boolean createFlag) {
kmcpeakeb172d5f2015-12-10 11:30:43 +0000232 this.device = device;
233 this.createFlag = createFlag;
234 }
235
236 @Override
237 public void run() {
238 if (createFlag) {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700239 log.debug("Trying to create Device Info on ONOS core");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000240 advertiseDevices();
241 } else {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700242 log.debug("Trying to remove Device Info on ONOS core");
kmcpeakeb172d5f2015-12-10 11:30:43 +0000243 removeDevices();
244 }
245 }
246
247 /**
248 * For each SNMP Device, remove the entry from the device store.
249 */
250 private void removeDevices() {
251 if (device == null) {
252 log.warn("The Request SNMP Device is null, cannot proceed further");
253 return;
254 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700255 DeviceId did = device.deviceId();
256 if (controller.getDevice(did) == null) {
257 log.error("BAD Request: 'Currently device is not discovered, "
258 + "so cannot remove/disconnect the device: "
259 + device.deviceInfo() + "'");
260 return;
kmcpeakeb172d5f2015-12-10 11:30:43 +0000261 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700262 providerService.deviceDisconnected(did);
263 device.disconnect();
264 controller.removeDevice(did);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000265 }
266
267 /**
268 * Initialize SNMP Device object, and notify core saying device connected.
269 */
270 private void advertiseDevices() {
271 try {
272 if (device == null) {
273 log.warn("The Request SNMP Device is null, cannot proceed further");
274 return;
275 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700276 DeviceId did = device.deviceId();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000277 ChassisId cid = new ChassisId();
278
Marc De Leenheerc662d322016-02-18 16:05:10 -0800279 SparseAnnotations annotations = DefaultAnnotations.builder()
280 .set(AnnotationKeys.PROTOCOL, SCHEME.toUpperCase())
281 .build();
kmcpeakeb172d5f2015-12-10 11:30:43 +0000282
283 DeviceDescription desc = new DefaultDeviceDescription(
Marc De Leenheerc662d322016-02-18 16:05:10 -0800284 did.uri(), Device.Type.OTHER, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, cid, annotations);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000285
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700286 log.debug("Persisting Device " + did.uri().toString());
kmcpeakeb172d5f2015-12-10 11:30:43 +0000287
Ray Milkey6b1acfc2018-09-05 16:59:17 -0700288 controller.addDevice(device);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000289 providerService.deviceConnected(did, desc);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700290 log.info("Added device to ONOS core. Device Info: "
291 + device.deviceInfo() + " " + did.uri().toString());
292 //FIXME this description will be populated only if driver is pushed from outside
Frank Wangd8ab0962017-08-11 11:09:30 +0800293 // because otherwise default driver is used
Marc De Leenheerc662d322016-02-18 16:05:10 -0800294 Device d = deviceService.getDevice(did);
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700295 if (d.is(DeviceDescriptionDiscovery.class)) {
296 DeviceDescriptionDiscovery descriptionDiscovery = d.as(DeviceDescriptionDiscovery.class);
297 DeviceDescription description = descriptionDiscovery.discoverDeviceDetails();
Andrea Campanella6c71a052016-04-22 11:56:31 -0700298 if (description != null) {
299 deviceStore.createOrUpdateDevice(
300 new ProviderId("snmp", "org.onosproject.provider.device"),
301 did, description);
302 } else {
303 log.info("No other description given for device {}", d.id());
304 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700305 providerService.updatePorts(did, descriptionDiscovery.discoverPortDetails());
Marc De Leenheerc662d322016-02-18 16:05:10 -0800306 } else {
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700307 log.warn("No populate description and ports behaviour for device {}", did);
Marc De Leenheerc662d322016-02-18 16:05:10 -0800308 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000309 } catch (Exception e) {
310 log.error("Error while initializing session for the device: "
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700311 + (device != null ? device.deviceInfo() : null), e);
kmcpeakeb172d5f2015-12-10 11:30:43 +0000312 }
313 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000314 }
315
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700316 private class InternalNetworkConfigListener implements NetworkConfigListener {
317
318
319 @Override
320 public void event(NetworkConfigEvent event) {
Andrea Campanella59b549d2017-04-14 21:58:16 +0200321 if (event.configClass().equals(SnmpDeviceConfig.class)) {
322 connectDevices();
323 } else {
324 log.warn("Injecting device via this Json is deprecated, " +
325 "please put configuration under devices/");
Andrea Campanella59b549d2017-04-14 21:58:16 +0200326 }
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700327 }
328
329 @Override
330 public boolean isRelevant(NetworkConfigEvent event) {
Ray Milkey4ad4a242018-02-13 13:54:40 -0800331 return (event.configClass().equals(SnmpDeviceConfig.class)) &&
Andrea Campanellac2d754b2016-03-29 17:51:07 -0700332 (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
333 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED);
334 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000335 }
Saurav Dasa2d37502016-03-25 17:50:40 -0700336
337 @Override
338 public void changePortState(DeviceId deviceId, PortNumber portNumber,
339 boolean enable) {
340 // TODO if required
341 }
kmcpeakeb172d5f2015-12-10 11:30:43 +0000342}