blob: 1baa76050068d183b23e6ab3d78b12780c4f2773 [file] [log] [blame]
Laszlo Papp9655b182017-01-31 13:01:45 -08001/*
2 * Copyright 2017-present Open Networking Foundation
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 */
16
17package org.onosproject.provider.snmp.alarm.impl;
18
19import com.google.common.collect.ImmutableList;
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;
Laszlo Papp9655b182017-01-31 13:01:45 -080026import org.onlab.packet.IpAddress;
27import org.onosproject.cluster.ClusterService;
28import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
Thomas Vachuska52f2cd12018-11-08 21:20:04 -080030import org.onosproject.alarm.Alarm;
31import org.onosproject.alarm.AlarmProvider;
32import org.onosproject.alarm.AlarmProviderRegistry;
33import org.onosproject.alarm.AlarmProviderService;
34import org.onosproject.alarm.DeviceAlarmConfig;
Laszlo Papp9655b182017-01-31 13:01:45 -080035import org.onosproject.mastership.MastershipEvent;
36import org.onosproject.mastership.MastershipListener;
37import org.onosproject.mastership.MastershipService;
38import org.onosproject.net.DeviceId;
39import org.onosproject.net.device.DeviceEvent;
40import org.onosproject.net.device.DeviceListener;
41import org.onosproject.net.device.DeviceService;
42import org.onosproject.net.driver.DefaultDriverData;
43import org.onosproject.net.driver.DefaultDriverHandler;
44import org.onosproject.net.driver.Driver;
45import org.onosproject.net.driver.DriverData;
46import org.onosproject.net.driver.DriverService;
47import org.onosproject.net.provider.AbstractProvider;
48import org.onosproject.net.provider.ProviderId;
49import org.onosproject.snmp.SnmpController;
50import org.onosproject.snmp.SnmpDevice;
51import org.osgi.service.component.ComponentContext;
52import org.slf4j.Logger;
53import org.snmp4j.CommandResponder;
54import org.snmp4j.CommandResponderEvent;
55import org.snmp4j.Snmp;
56import org.snmp4j.TransportMapping;
57import org.snmp4j.smi.Address;
58import org.snmp4j.smi.GenericAddress;
59import org.snmp4j.smi.TcpAddress;
60import org.snmp4j.smi.UdpAddress;
61import org.snmp4j.transport.DefaultTcpTransportMapping;
62import org.snmp4j.transport.DefaultUdpTransportMapping;
63
64import java.io.IOException;
65import java.net.URI;
66import java.util.HashMap;
67import java.util.Map;
68import java.util.Set;
69
70import static org.slf4j.LoggerFactory.getLogger;
71
72/**
73 * Provider which will listen for traps generated SNMP devices and configure
74 * the devices with the Ip and Protocol fo the end point to send traps to.
75 */
76@Component(immediate = true)
77public class SnmpAlarmProvider extends AbstractProvider
78 implements AlarmProvider {
79
80 public static final String COLON = ":";
81 private final Logger log = getLogger(SnmpAlarmProvider.class);
82
Ray Milkeyd84f89b2018-08-17 14:54:17 -070083 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Laszlo Papp9655b182017-01-31 13:01:45 -080084 protected SnmpController controller;
85
Ray Milkeyd84f89b2018-08-17 14:54:17 -070086 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Laszlo Papp9655b182017-01-31 13:01:45 -080087 protected AlarmProviderRegistry providerRegistry;
88
Ray Milkeyd84f89b2018-08-17 14:54:17 -070089 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Laszlo Papp9655b182017-01-31 13:01:45 -080090 protected DriverService driverService;
91
Ray Milkeyd84f89b2018-08-17 14:54:17 -070092 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Laszlo Papp9655b182017-01-31 13:01:45 -080093 protected MastershipService mastershipService;
94
Ray Milkeyd84f89b2018-08-17 14:54:17 -070095 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Laszlo Papp9655b182017-01-31 13:01:45 -080096 protected DeviceService deviceService;
97
Ray Milkeyd84f89b2018-08-17 14:54:17 -070098 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Laszlo Papp9655b182017-01-31 13:01:45 -080099 protected CoreService coreService;
100
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700101 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Laszlo Papp9655b182017-01-31 13:01:45 -0800102 protected ClusterService clusterService;
103
104 private static final String APP_NAME = "org.onosproject.snmp";
105 private static final String SCHEME = "snmp";
106
107 protected AlarmProviderService providerService;
108
109 protected ApplicationId appId;
110
111 protected final DeviceListener deviceListener = new InternalDeviceListener();
112
113 protected final MastershipListener mastershipListener = new InternalMastershipListener();
114
115 protected final CommandResponder internalCommandResponder = new InternalCommandResponder();
116
117 private IpAddress localIp;
118
119 private final Map<Integer, Snmp> portSessionMap = new HashMap<>();
120
121 private Snmp snmp;
122
123
124 /**
125 * Creates a provider with the supplier identifier.
126 */
127 public SnmpAlarmProvider() {
128 super(new ProviderId("snmp", "org.onosproject.provider.alarm"));
129 }
130
131 @Activate
132 public void activate(ComponentContext context) {
133
134 providerService = providerRegistry.register(this);
135 appId = coreService.registerApplication(APP_NAME);
136 deviceService.addListener(deviceListener);
137 mastershipService.addListener(mastershipListener);
138 controller.getDevices().stream().forEach(d -> {
139 triggerProbe(d.deviceId());
Laszlo Papp9655b182017-01-31 13:01:45 -0800140 });
141 localIp = clusterService.getLocalNode().ip();
142 log.info("Started");
143 }
144
145 @Deactivate
146 public void deactivate(ComponentContext context) {
147 for (Map.Entry<Integer, Snmp> entry : portSessionMap.entrySet()) {
148 try {
149 entry.getValue().close();
150 } catch (IOException e) {
151 log.warn("Can't close SNMP notification session on Ip {} and Port {}",
152 localIp, entry.getKey(), e);
153 }
154 }
155 mastershipService.addListener(mastershipListener);
156 deviceService.removeListener(deviceListener);
157 providerRegistry.unregister(this);
158 providerService = null;
159 log.info("Stopped");
160 }
161
162 @Modified
163 public void modified() {
164 log.info("Modified");
165 }
166
167 @Override
168 public void triggerProbe(DeviceId deviceId) {
169 requestTraps(deviceId);
Laszlo Papp10f0d512018-06-18 15:35:51 +0100170 configureListeningConnection(controller.getDevice(deviceId));
Laszlo Papp9655b182017-01-31 13:01:45 -0800171 }
172
173 private void configureListeningConnection(SnmpDevice device) {
174 int notificationPort = device.getNotificationPort();
175 if (notificationPort == 0 || portSessionMap.containsKey(notificationPort)) {
176 return;
177 }
178 String protocol = device.getProtocol();
179 try {
180 Address listenAddress = GenericAddress.parse(protocol +
181 ":" + localIp.toString() +
182 "/" + notificationPort);
183 TransportMapping tm;
184 if (protocol == GenericAddress.TYPE_TCP) {
185 tm = new DefaultTcpTransportMapping((TcpAddress) listenAddress);
186 } else {
187 tm = new DefaultUdpTransportMapping((UdpAddress) listenAddress);
188 }
189 snmp = new Snmp(tm);
190 snmp.addCommandResponder(internalCommandResponder);
191 snmp.listen();
192 log.info("Initiated SNMP notification connection on Ip {} and Port {}",
193 localIp.toString(), notificationPort);
194 } catch (IOException e) {
195 log.error("Can't initiate SNMP transport on Protocol {}, Ip {} and Port {}",
196 protocol, localIp, notificationPort, e);
197 return;
198 }
199
200 portSessionMap.put(notificationPort, snmp);
201 }
202
203 private boolean requestTraps(DeviceId deviceId) {
204 SnmpDevice device = controller.getDevice(deviceId);
205 DeviceAlarmConfig alarmTranslator = getAlarmTranslator(device);
206 if (alarmTranslator != null) {
207 return alarmTranslator.configureDevice(localIp, device.getNotificationPort(),
208 device.getNotificationProtocol());
209 } else {
210 log.warn("Device {} does not support alarms.", deviceId);
211 return false;
212 }
213 }
214
215 private DeviceAlarmConfig getAlarmTranslator(SnmpDevice device) {
216 Driver deviceDriver = driverService.getDriver(device.deviceId());
217 if (deviceDriver != null && deviceDriver.hasBehaviour(DeviceAlarmConfig.class)) {
218 DriverData driverData = new DefaultDriverData(deviceDriver, device.deviceId());
219 DeviceAlarmConfig alarmTranslator = deviceDriver
220 .createBehaviour(driverData, DeviceAlarmConfig.class);
221 alarmTranslator.setHandler(new DefaultDriverHandler(driverData));
222 return alarmTranslator;
223 } else {
224 log.warn("Device does not support alarm {}", device.deviceId());
225 }
226 return null;
227 }
228
229 private class InternalCommandResponder implements CommandResponder {
230 @Override
231 public void processPdu(CommandResponderEvent event) {
232 try {
233 log.debug("received trap {}", event);
234 String[] deviceInfo = event.getPeerAddress().toString().split("/");
235
236 //TODO This should be done via device service.
237 //searching only for Ip since the port from which the trap is sent
238 // could be different from the one used for SNMP
239 SnmpDevice device = controller.getDevice(new URI(deviceInfo[0]));
240 if (device != null) {
241 DeviceId deviceId = DeviceId.deviceId(SCHEME + COLON + deviceInfo[0]
242 + COLON + device.getSnmpPort());
243 DeviceAlarmConfig alarmTranslator = getAlarmTranslator(controller.getDevice(deviceId));
244 if (alarmTranslator != null) {
245 Set<Alarm> alarms = alarmTranslator.translateAlarms(ImmutableList.of(event));
246 providerService.updateAlarmList(deviceId, alarms);
247 } else {
248 log.warn("Device {} does not support alarm", device.deviceId());
249 }
250 } else {
251 log.error("Device {} does not exist in ONOS SNMP subsystem", deviceInfo[0]);
252 }
253 //Catching generic exception due to otherwise hidden URISyntax
254 } catch (Exception e) {
255 log.error("Exception while processing PDU {}", e);
256 }
257 }
258 }
259
260 private class InternalDeviceListener implements DeviceListener {
261
262 @Override
263 public void event(DeviceEvent event) {
264 DeviceId deviceId = event.subject().id();
265 switch (event.type()) {
266 case DEVICE_ADDED:
267 triggerProbe(deviceId);
Ray Milkey93a5d392018-06-05 11:29:12 -0700268 break;
Laszlo Papp9655b182017-01-31 13:01:45 -0800269 case DEVICE_UPDATED:
270 triggerProbe(deviceId);
Ray Milkey93a5d392018-06-05 11:29:12 -0700271 break;
Laszlo Papp9655b182017-01-31 13:01:45 -0800272 default:
273 break;
274 }
275 }
276
277 @Override
278 public boolean isRelevant(DeviceEvent event) {
279 return event.subject().id().toString().startsWith(SCHEME)
280 && mastershipService.isLocalMaster(event.subject().id());
281 }
282 }
283
284 private class InternalMastershipListener implements MastershipListener {
285
286 @Override
287 public void event(MastershipEvent event) {
288 triggerProbe(event.subject());
289 }
290
291 @Override
292 public boolean isRelevant(MastershipEvent event) {
293 return event.subject().toString().startsWith(SCHEME)
294 && mastershipService.isLocalMaster(event.subject());
295 }
296 }
297}