blob: 00178bc0bc25dae1190f6aad8447745cb82296ea [file] [log] [blame]
andreaeb70a942015-10-16 21:34:46 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
andreaeb70a942015-10-16 21:34:46 -07003 *
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.netconf.ctl;
18
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
Andreas Papazois4752cfa2016-04-25 14:52:12 +030022import org.apache.felix.scr.annotations.Modified;
23import org.apache.felix.scr.annotations.Property;
Andrea Campanella7e6200a2016-03-21 09:48:40 -070024import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
andreaeb70a942015-10-16 21:34:46 -070026import org.apache.felix.scr.annotations.Service;
27import org.onlab.packet.IpAddress;
Andreas Papazois4752cfa2016-04-25 14:52:12 +030028import org.onosproject.cfg.ComponentConfigService;
Andrea Campanella7e6200a2016-03-21 09:48:40 -070029import org.onosproject.net.Device;
andreaeb70a942015-10-16 21:34:46 -070030import org.onosproject.net.DeviceId;
Andrea Campanella7e6200a2016-03-21 09:48:40 -070031import org.onosproject.net.device.DeviceService;
32import org.onosproject.net.key.DeviceKeyId;
33import org.onosproject.net.key.DeviceKeyService;
34import org.onosproject.net.key.UsernamePassword;
andreaeb70a942015-10-16 21:34:46 -070035import org.onosproject.netconf.NetconfController;
36import org.onosproject.netconf.NetconfDevice;
Andrea Campanella950310c2016-02-12 18:14:38 -080037import org.onosproject.netconf.NetconfDeviceFactory;
andreaeb70a942015-10-16 21:34:46 -070038import org.onosproject.netconf.NetconfDeviceInfo;
39import org.onosproject.netconf.NetconfDeviceListener;
Andrea Campanella2464dc32016-02-17 17:54:53 -080040import org.onosproject.netconf.NetconfDeviceOutputEvent;
41import org.onosproject.netconf.NetconfDeviceOutputEventListener;
Andrea Campanella101417d2015-12-11 17:58:07 -080042import org.onosproject.netconf.NetconfException;
andreaeb70a942015-10-16 21:34:46 -070043import org.osgi.service.component.ComponentContext;
44import org.slf4j.Logger;
45import org.slf4j.LoggerFactory;
46
Andrea Campanella7e6200a2016-03-21 09:48:40 -070047import java.util.Arrays;
Andreas Papazois4752cfa2016-04-25 14:52:12 +030048import java.util.Dictionary;
andreaeb70a942015-10-16 21:34:46 -070049import java.util.Map;
50import java.util.Set;
51import java.util.concurrent.ConcurrentHashMap;
52import java.util.concurrent.CopyOnWriteArraySet;
53
Andreas Papazois4752cfa2016-04-25 14:52:12 +030054import static com.google.common.base.Strings.isNullOrEmpty;
55import static org.onlab.util.Tools.get;
56
andreaeb70a942015-10-16 21:34:46 -070057/**
58 * The implementation of NetconfController.
59 */
60@Component(immediate = true)
61@Service
62public class NetconfControllerImpl implements NetconfController {
Sean Condon334ad692016-12-13 17:56:56 +000063 private static final int DEFAULT_CONNECT_TIMEOUT_SECONDS = 5;
64 private static final String PROP_NETCONF_CONNECT_TIMEOUT = "netconfConnectTimeout";
65 @Property(name = PROP_NETCONF_CONNECT_TIMEOUT, intValue = DEFAULT_CONNECT_TIMEOUT_SECONDS,
66 label = "Time (in seconds) to wait for a NETCONF connect.")
67 protected static int netconfConnectTimeout = DEFAULT_CONNECT_TIMEOUT_SECONDS;
68
Andreas Papazois4752cfa2016-04-25 14:52:12 +030069 private static final String PROP_NETCONF_REPLY_TIMEOUT = "netconfReplyTimeout";
70 private static final int DEFAULT_REPLY_TIMEOUT_SECONDS = 5;
71 @Property(name = PROP_NETCONF_REPLY_TIMEOUT, intValue = DEFAULT_REPLY_TIMEOUT_SECONDS,
72 label = "Time (in seconds) waiting for a NetConf reply")
73 protected static int netconfReplyTimeout = DEFAULT_REPLY_TIMEOUT_SECONDS;
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected ComponentConfigService cfgService;
77
Andrea Campanella7e6200a2016-03-21 09:48:40 -070078 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected DeviceService deviceService;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected DeviceKeyService deviceKeyService;
andreaeb70a942015-10-16 21:34:46 -070083
84 public static final Logger log = LoggerFactory
85 .getLogger(NetconfControllerImpl.class);
86
Andrea Campanella8b1cb672016-01-25 13:58:58 -080087 private Map<DeviceId, NetconfDevice> netconfDeviceMap = new ConcurrentHashMap<>();
andreaeb70a942015-10-16 21:34:46 -070088
Andrea Campanella2464dc32016-02-17 17:54:53 -080089 private final NetconfDeviceOutputEventListener downListener = new DeviceDownEventListener();
90
andreaeb70a942015-10-16 21:34:46 -070091 protected Set<NetconfDeviceListener> netconfDeviceListeners = new CopyOnWriteArraySet<>();
Andrea Campanella950310c2016-02-12 18:14:38 -080092 protected NetconfDeviceFactory deviceFactory = new DefaultNetconfDeviceFactory();
andreaeb70a942015-10-16 21:34:46 -070093
94 @Activate
95 public void activate(ComponentContext context) {
Andreas Papazois4752cfa2016-04-25 14:52:12 +030096 cfgService.registerProperties(getClass());
97 modified(context);
andreaeb70a942015-10-16 21:34:46 -070098 log.info("Started");
99 }
100
101 @Deactivate
102 public void deactivate() {
Andreas Papazois4752cfa2016-04-25 14:52:12 +0300103 cfgService.unregisterProperties(getClass(), false);
andreaeb70a942015-10-16 21:34:46 -0700104 netconfDeviceMap.clear();
105 log.info("Stopped");
106 }
107
Andreas Papazois4752cfa2016-04-25 14:52:12 +0300108 @Modified
109 public void modified(ComponentContext context) {
110 if (context == null) {
111 netconfReplyTimeout = DEFAULT_REPLY_TIMEOUT_SECONDS;
Sean Condon334ad692016-12-13 17:56:56 +0000112 netconfConnectTimeout = DEFAULT_CONNECT_TIMEOUT_SECONDS;
Andreas Papazois4752cfa2016-04-25 14:52:12 +0300113 log.info("No component configuration");
114 return;
115 }
116
117 Dictionary<?, ?> properties = context.getProperties();
118
119 int newNetconfReplyTimeout;
Sean Condon334ad692016-12-13 17:56:56 +0000120 int newNetconfConnectTimeout;
Andreas Papazois4752cfa2016-04-25 14:52:12 +0300121 try {
122 String s = get(properties, PROP_NETCONF_REPLY_TIMEOUT);
123 newNetconfReplyTimeout = isNullOrEmpty(s) ?
124 netconfReplyTimeout : Integer.parseInt(s.trim());
Sean Condon334ad692016-12-13 17:56:56 +0000125
126 s = get(properties, PROP_NETCONF_CONNECT_TIMEOUT);
127 newNetconfConnectTimeout = isNullOrEmpty(s) ?
128 netconfConnectTimeout : Integer.parseInt(s.trim());
129
Andreas Papazois4752cfa2016-04-25 14:52:12 +0300130 } catch (NumberFormatException e) {
131 log.warn("Component configuration had invalid value", e);
132 return;
133 }
134
Sean Condon334ad692016-12-13 17:56:56 +0000135 if (newNetconfConnectTimeout < 0) {
136 log.warn("netconfConnectTimeout is invalid - less than 0");
137 return;
138 } else if (newNetconfReplyTimeout <= 0) {
139 log.warn("netconfReplyTimeout is invalid - 0 or less.");
140 return;
141 }
142
Andreas Papazois4752cfa2016-04-25 14:52:12 +0300143 netconfReplyTimeout = newNetconfReplyTimeout;
Sean Condon334ad692016-12-13 17:56:56 +0000144 netconfConnectTimeout = newNetconfConnectTimeout;
145 log.info("Settings: {} = {}, {} = {}",
146 PROP_NETCONF_REPLY_TIMEOUT, netconfReplyTimeout, PROP_NETCONF_CONNECT_TIMEOUT, netconfConnectTimeout);
Andreas Papazois4752cfa2016-04-25 14:52:12 +0300147 }
148
andreaeb70a942015-10-16 21:34:46 -0700149 @Override
150 public void addDeviceListener(NetconfDeviceListener listener) {
151 if (!netconfDeviceListeners.contains(listener)) {
152 netconfDeviceListeners.add(listener);
153 }
154 }
155
156 @Override
157 public void removeDeviceListener(NetconfDeviceListener listener) {
158 netconfDeviceListeners.remove(listener);
159 }
160
161 @Override
162 public NetconfDevice getNetconfDevice(DeviceId deviceInfo) {
163 return netconfDeviceMap.get(deviceInfo);
164 }
165
166 @Override
167 public NetconfDevice getNetconfDevice(IpAddress ip, int port) {
andreaeb70a942015-10-16 21:34:46 -0700168 for (DeviceId info : netconfDeviceMap.keySet()) {
Andrea Campanella57efbb22016-02-11 14:21:41 -0800169 if (info.uri().getSchemeSpecificPart().equals(ip.toString() + ":" + port)) {
andreaeb70a942015-10-16 21:34:46 -0700170 return netconfDeviceMap.get(info);
171 }
172 }
Andrea Campanella1cd641b2015-12-07 17:28:34 -0800173 return null;
andreaeb70a942015-10-16 21:34:46 -0700174 }
175
176 @Override
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700177 public NetconfDevice connectDevice(DeviceId deviceId) throws NetconfException {
178 if (netconfDeviceMap.containsKey(deviceId)) {
179 log.debug("Device {} is already present", deviceId);
180 return netconfDeviceMap.get(deviceId);
andreaeb70a942015-10-16 21:34:46 -0700181 } else {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700182 log.debug("Creating NETCONF device {}", deviceId);
183 Device device = deviceService.getDevice(deviceId);
184 String ip;
185 int port;
186 if (device != null) {
187 ip = device.annotations().value("ipaddress");
188 port = Integer.parseInt(device.annotations().value("port"));
189 } else {
190 String[] info = deviceId.toString().split(":");
191 if (info.length == 3) {
192 ip = info[1];
193 port = Integer.parseInt(info[2]);
194 } else {
195 ip = Arrays.asList(info).stream().filter(el -> !el.equals(info[0])
196 && !el.equals(info[info.length - 1]))
197 .reduce((t, u) -> t + ":" + u)
198 .get();
199 log.debug("ip v6 {}", ip);
200 port = Integer.parseInt(info[info.length - 1]);
201 }
202 }
203 try {
204 UsernamePassword deviceKey = deviceKeyService.getDeviceKey(
205 DeviceKeyId.deviceKeyId(deviceId.toString())).asUsernamePassword();
206
207 NetconfDeviceInfo deviceInfo = new NetconfDeviceInfo(deviceKey.username(),
208 deviceKey.password(),
209 IpAddress.valueOf(ip),
210 port);
211 NetconfDevice netconfDevicedevice = createDevice(deviceInfo);
212
213 netconfDevicedevice.getSession().addDeviceOutputListener(downListener);
214 return netconfDevicedevice;
215 } catch (NullPointerException e) {
216 throw new NetconfException("No Device Key for device " + deviceId, e);
217 }
andreaeb70a942015-10-16 21:34:46 -0700218 }
219 }
220
221 @Override
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700222 public void disconnectDevice(DeviceId deviceId, boolean remove) {
223 if (!netconfDeviceMap.containsKey(deviceId)) {
224 log.warn("Device {} is not present", deviceId);
andreaeb70a942015-10-16 21:34:46 -0700225 } else {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700226 stopDevice(deviceId, remove);
andreaeb70a942015-10-16 21:34:46 -0700227 }
228 }
229
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700230 private void stopDevice(DeviceId deviceId, boolean remove) {
231 netconfDeviceMap.get(deviceId).disconnect();
232 netconfDeviceMap.remove(deviceId);
233 if (remove) {
Andrea Campanella86294db2016-03-07 11:42:49 -0800234 for (NetconfDeviceListener l : netconfDeviceListeners) {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700235 l.deviceRemoved(deviceId);
236 }
237 }
238 }
239
240 @Override
241 public void removeDevice(DeviceId deviceId) {
242 if (!netconfDeviceMap.containsKey(deviceId)) {
243 log.warn("Device {} is not present", deviceId);
244 for (NetconfDeviceListener l : netconfDeviceListeners) {
245 l.deviceRemoved(deviceId);
246 }
247 } else {
248 netconfDeviceMap.remove(deviceId);
249 for (NetconfDeviceListener l : netconfDeviceListeners) {
250 l.deviceRemoved(deviceId);
Andrea Campanella86294db2016-03-07 11:42:49 -0800251 }
252 }
253 }
254
Andrea Campanella101417d2015-12-11 17:58:07 -0800255 private NetconfDevice createDevice(NetconfDeviceInfo deviceInfo) throws NetconfException {
Andrea Campanella950310c2016-02-12 18:14:38 -0800256 NetconfDevice netconfDevice = deviceFactory.createNetconfDevice(deviceInfo);
Andrea Campanella087ceb92015-12-07 09:58:34 -0800257 netconfDeviceMap.put(deviceInfo.getDeviceId(), netconfDevice);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700258 for (NetconfDeviceListener l : netconfDeviceListeners) {
259 l.deviceAdded(deviceInfo.getDeviceId());
260 }
andreaeb70a942015-10-16 21:34:46 -0700261 return netconfDevice;
262 }
263
andreaeb70a942015-10-16 21:34:46 -0700264
265 @Override
266 public Map<DeviceId, NetconfDevice> getDevicesMap() {
267 return netconfDeviceMap;
268 }
Andrea Campanella950310c2016-02-12 18:14:38 -0800269
Andrea Campanella86294db2016-03-07 11:42:49 -0800270 @Override
271 public Set<DeviceId> getNetconfDevices() {
272 return netconfDeviceMap.keySet();
273 }
274
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700275
276
Andrea Campanella950310c2016-02-12 18:14:38 -0800277 //Device factory for the specific NetconfDeviceImpl
278 private class DefaultNetconfDeviceFactory implements NetconfDeviceFactory {
279
280 @Override
281 public NetconfDevice createNetconfDevice(NetconfDeviceInfo netconfDeviceInfo) throws NetconfException {
282 return new DefaultNetconfDevice(netconfDeviceInfo);
283 }
284 }
Andrea Campanella2464dc32016-02-17 17:54:53 -0800285
286 //Listener for closed session with devices, gets triggered whe devices goes down
287 // or sends the endpattern ]]>]]>
288 private class DeviceDownEventListener implements NetconfDeviceOutputEventListener {
289
290 @Override
291 public void event(NetconfDeviceOutputEvent event) {
292 if (event.type().equals(NetconfDeviceOutputEvent.Type.DEVICE_UNREGISTERED)) {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700293 removeDevice(event.getDeviceInfo().getDeviceId());
Andrea Campanella2464dc32016-02-17 17:54:53 -0800294 }
295 }
296
297 @Override
298 public boolean isRelevant(NetconfDeviceOutputEvent event) {
299 return getDevicesMap().containsKey(event.getDeviceInfo().getDeviceId());
300 }
301 }
andreaeb70a942015-10-16 21:34:46 -0700302}