blob: 0e34a390d8cb95697dee92793585e74c56df2a5a [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 {
Andreas Papazois4752cfa2016-04-25 14:52:12 +030063 private static final String PROP_NETCONF_REPLY_TIMEOUT = "netconfReplyTimeout";
64 private static final int DEFAULT_REPLY_TIMEOUT_SECONDS = 5;
65 @Property(name = PROP_NETCONF_REPLY_TIMEOUT, intValue = DEFAULT_REPLY_TIMEOUT_SECONDS,
66 label = "Time (in seconds) waiting for a NetConf reply")
67 protected static int netconfReplyTimeout = DEFAULT_REPLY_TIMEOUT_SECONDS;
68
69 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 protected ComponentConfigService cfgService;
71
Andrea Campanella7e6200a2016-03-21 09:48:40 -070072 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected DeviceService deviceService;
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected DeviceKeyService deviceKeyService;
andreaeb70a942015-10-16 21:34:46 -070077
78 public static final Logger log = LoggerFactory
79 .getLogger(NetconfControllerImpl.class);
80
Andrea Campanella8b1cb672016-01-25 13:58:58 -080081 private Map<DeviceId, NetconfDevice> netconfDeviceMap = new ConcurrentHashMap<>();
andreaeb70a942015-10-16 21:34:46 -070082
Andrea Campanella2464dc32016-02-17 17:54:53 -080083 private final NetconfDeviceOutputEventListener downListener = new DeviceDownEventListener();
84
andreaeb70a942015-10-16 21:34:46 -070085 protected Set<NetconfDeviceListener> netconfDeviceListeners = new CopyOnWriteArraySet<>();
Andrea Campanella950310c2016-02-12 18:14:38 -080086 protected NetconfDeviceFactory deviceFactory = new DefaultNetconfDeviceFactory();
andreaeb70a942015-10-16 21:34:46 -070087
88 @Activate
89 public void activate(ComponentContext context) {
Andreas Papazois4752cfa2016-04-25 14:52:12 +030090 cfgService.registerProperties(getClass());
91 modified(context);
andreaeb70a942015-10-16 21:34:46 -070092 log.info("Started");
93 }
94
95 @Deactivate
96 public void deactivate() {
Andreas Papazois4752cfa2016-04-25 14:52:12 +030097 cfgService.unregisterProperties(getClass(), false);
andreaeb70a942015-10-16 21:34:46 -070098 netconfDeviceMap.clear();
99 log.info("Stopped");
100 }
101
Andreas Papazois4752cfa2016-04-25 14:52:12 +0300102 @Modified
103 public void modified(ComponentContext context) {
104 if (context == null) {
105 netconfReplyTimeout = DEFAULT_REPLY_TIMEOUT_SECONDS;
106 log.info("No component configuration");
107 return;
108 }
109
110 Dictionary<?, ?> properties = context.getProperties();
111
112 int newNetconfReplyTimeout;
113 try {
114 String s = get(properties, PROP_NETCONF_REPLY_TIMEOUT);
115 newNetconfReplyTimeout = isNullOrEmpty(s) ?
116 netconfReplyTimeout : Integer.parseInt(s.trim());
117 } catch (NumberFormatException e) {
118 log.warn("Component configuration had invalid value", e);
119 return;
120 }
121
122 netconfReplyTimeout = newNetconfReplyTimeout;
123 log.info("Settings: {} = {}", PROP_NETCONF_REPLY_TIMEOUT, netconfReplyTimeout);
124 }
125
andreaeb70a942015-10-16 21:34:46 -0700126 @Override
127 public void addDeviceListener(NetconfDeviceListener listener) {
128 if (!netconfDeviceListeners.contains(listener)) {
129 netconfDeviceListeners.add(listener);
130 }
131 }
132
133 @Override
134 public void removeDeviceListener(NetconfDeviceListener listener) {
135 netconfDeviceListeners.remove(listener);
136 }
137
138 @Override
139 public NetconfDevice getNetconfDevice(DeviceId deviceInfo) {
140 return netconfDeviceMap.get(deviceInfo);
141 }
142
143 @Override
144 public NetconfDevice getNetconfDevice(IpAddress ip, int port) {
andreaeb70a942015-10-16 21:34:46 -0700145 for (DeviceId info : netconfDeviceMap.keySet()) {
Andrea Campanella57efbb22016-02-11 14:21:41 -0800146 if (info.uri().getSchemeSpecificPart().equals(ip.toString() + ":" + port)) {
andreaeb70a942015-10-16 21:34:46 -0700147 return netconfDeviceMap.get(info);
148 }
149 }
Andrea Campanella1cd641b2015-12-07 17:28:34 -0800150 return null;
andreaeb70a942015-10-16 21:34:46 -0700151 }
152
153 @Override
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700154 public NetconfDevice connectDevice(DeviceId deviceId) throws NetconfException {
155 if (netconfDeviceMap.containsKey(deviceId)) {
156 log.debug("Device {} is already present", deviceId);
157 return netconfDeviceMap.get(deviceId);
andreaeb70a942015-10-16 21:34:46 -0700158 } else {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700159 log.debug("Creating NETCONF device {}", deviceId);
160 Device device = deviceService.getDevice(deviceId);
161 String ip;
162 int port;
163 if (device != null) {
164 ip = device.annotations().value("ipaddress");
165 port = Integer.parseInt(device.annotations().value("port"));
166 } else {
167 String[] info = deviceId.toString().split(":");
168 if (info.length == 3) {
169 ip = info[1];
170 port = Integer.parseInt(info[2]);
171 } else {
172 ip = Arrays.asList(info).stream().filter(el -> !el.equals(info[0])
173 && !el.equals(info[info.length - 1]))
174 .reduce((t, u) -> t + ":" + u)
175 .get();
176 log.debug("ip v6 {}", ip);
177 port = Integer.parseInt(info[info.length - 1]);
178 }
179 }
180 try {
181 UsernamePassword deviceKey = deviceKeyService.getDeviceKey(
182 DeviceKeyId.deviceKeyId(deviceId.toString())).asUsernamePassword();
183
184 NetconfDeviceInfo deviceInfo = new NetconfDeviceInfo(deviceKey.username(),
185 deviceKey.password(),
186 IpAddress.valueOf(ip),
187 port);
188 NetconfDevice netconfDevicedevice = createDevice(deviceInfo);
189
190 netconfDevicedevice.getSession().addDeviceOutputListener(downListener);
191 return netconfDevicedevice;
192 } catch (NullPointerException e) {
193 throw new NetconfException("No Device Key for device " + deviceId, e);
194 }
andreaeb70a942015-10-16 21:34:46 -0700195 }
196 }
197
198 @Override
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700199 public void disconnectDevice(DeviceId deviceId, boolean remove) {
200 if (!netconfDeviceMap.containsKey(deviceId)) {
201 log.warn("Device {} is not present", deviceId);
andreaeb70a942015-10-16 21:34:46 -0700202 } else {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700203 stopDevice(deviceId, remove);
andreaeb70a942015-10-16 21:34:46 -0700204 }
205 }
206
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700207 private void stopDevice(DeviceId deviceId, boolean remove) {
208 netconfDeviceMap.get(deviceId).disconnect();
209 netconfDeviceMap.remove(deviceId);
210 if (remove) {
Andrea Campanella86294db2016-03-07 11:42:49 -0800211 for (NetconfDeviceListener l : netconfDeviceListeners) {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700212 l.deviceRemoved(deviceId);
213 }
214 }
215 }
216
217 @Override
218 public void removeDevice(DeviceId deviceId) {
219 if (!netconfDeviceMap.containsKey(deviceId)) {
220 log.warn("Device {} is not present", deviceId);
221 for (NetconfDeviceListener l : netconfDeviceListeners) {
222 l.deviceRemoved(deviceId);
223 }
224 } else {
225 netconfDeviceMap.remove(deviceId);
226 for (NetconfDeviceListener l : netconfDeviceListeners) {
227 l.deviceRemoved(deviceId);
Andrea Campanella86294db2016-03-07 11:42:49 -0800228 }
229 }
230 }
231
Andrea Campanella101417d2015-12-11 17:58:07 -0800232 private NetconfDevice createDevice(NetconfDeviceInfo deviceInfo) throws NetconfException {
Andrea Campanella950310c2016-02-12 18:14:38 -0800233 NetconfDevice netconfDevice = deviceFactory.createNetconfDevice(deviceInfo);
Andrea Campanella087ceb92015-12-07 09:58:34 -0800234 netconfDeviceMap.put(deviceInfo.getDeviceId(), netconfDevice);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700235 for (NetconfDeviceListener l : netconfDeviceListeners) {
236 l.deviceAdded(deviceInfo.getDeviceId());
237 }
andreaeb70a942015-10-16 21:34:46 -0700238 return netconfDevice;
239 }
240
andreaeb70a942015-10-16 21:34:46 -0700241
242 @Override
243 public Map<DeviceId, NetconfDevice> getDevicesMap() {
244 return netconfDeviceMap;
245 }
Andrea Campanella950310c2016-02-12 18:14:38 -0800246
Andrea Campanella86294db2016-03-07 11:42:49 -0800247 @Override
248 public Set<DeviceId> getNetconfDevices() {
249 return netconfDeviceMap.keySet();
250 }
251
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700252
253
Andrea Campanella950310c2016-02-12 18:14:38 -0800254 //Device factory for the specific NetconfDeviceImpl
255 private class DefaultNetconfDeviceFactory implements NetconfDeviceFactory {
256
257 @Override
258 public NetconfDevice createNetconfDevice(NetconfDeviceInfo netconfDeviceInfo) throws NetconfException {
259 return new DefaultNetconfDevice(netconfDeviceInfo);
260 }
261 }
Andrea Campanella2464dc32016-02-17 17:54:53 -0800262
263 //Listener for closed session with devices, gets triggered whe devices goes down
264 // or sends the endpattern ]]>]]>
265 private class DeviceDownEventListener implements NetconfDeviceOutputEventListener {
266
267 @Override
268 public void event(NetconfDeviceOutputEvent event) {
269 if (event.type().equals(NetconfDeviceOutputEvent.Type.DEVICE_UNREGISTERED)) {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700270 removeDevice(event.getDeviceInfo().getDeviceId());
Andrea Campanella2464dc32016-02-17 17:54:53 -0800271 }
272 }
273
274 @Override
275 public boolean isRelevant(NetconfDeviceOutputEvent event) {
276 return getDevicesMap().containsKey(event.getDeviceInfo().getDeviceId());
277 }
278 }
andreaeb70a942015-10-16 21:34:46 -0700279}