blob: 696617b435845fd159f1e6ecbf6ab6ce5bfc6579 [file] [log] [blame]
Sanjay Se8dcfee2015-04-23 10:07:08 +05301/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Sanjay Se8dcfee2015-04-23 10:07:08 +05303 *
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 */
andreaeb70a942015-10-16 21:34:46 -070016
Sanjay Se8dcfee2015-04-23 10:07:08 +053017package org.onosproject.provider.netconf.device.impl;
18
Michele Santuari00cc1f72016-09-08 17:05:24 +020019import com.google.common.base.Objects;
andreaeb70a942015-10-16 21:34:46 -070020import com.google.common.base.Preconditions;
Sanjay Se8dcfee2015-04-23 10:07:08 +053021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
Sanjay Se8dcfee2015-04-23 10:07:08 +053024import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.onlab.packet.ChassisId;
andreaeb70a942015-10-16 21:34:46 -070027import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
29import org.onosproject.incubator.net.config.basics.ConfigException;
Andrea Campanella7e6200a2016-03-21 09:48:40 -070030import org.onosproject.mastership.MastershipService;
Marc De Leenheerb0d131c2016-03-01 20:34:59 -080031import org.onosproject.net.AnnotationKeys;
andreaeb70a942015-10-16 21:34:46 -070032import org.onosproject.net.DefaultAnnotations;
Sanjay Se8dcfee2015-04-23 10:07:08 +053033import org.onosproject.net.Device;
34import org.onosproject.net.DeviceId;
35import org.onosproject.net.MastershipRole;
Saurav Dasa2d37502016-03-25 17:50:40 -070036import org.onosproject.net.PortNumber;
andreaeb70a942015-10-16 21:34:46 -070037import org.onosproject.net.SparseAnnotations;
Aaron Kruglikov17b4c852016-01-15 16:37:04 -080038import org.onosproject.net.behaviour.PortDiscovery;
andreaeb70a942015-10-16 21:34:46 -070039import org.onosproject.net.config.ConfigFactory;
40import org.onosproject.net.config.NetworkConfigEvent;
41import org.onosproject.net.config.NetworkConfigListener;
42import org.onosproject.net.config.NetworkConfigRegistry;
Sanjay Se8dcfee2015-04-23 10:07:08 +053043import org.onosproject.net.device.DefaultDeviceDescription;
44import org.onosproject.net.device.DeviceDescription;
Andrea Campanella6c71a052016-04-22 11:56:31 -070045import org.onosproject.net.device.DeviceDescriptionDiscovery;
Andrea Campanella7e6200a2016-03-21 09:48:40 -070046import org.onosproject.net.device.DeviceEvent;
47import org.onosproject.net.device.DeviceListener;
Sanjay Se8dcfee2015-04-23 10:07:08 +053048import org.onosproject.net.device.DeviceProvider;
49import org.onosproject.net.device.DeviceProviderRegistry;
50import org.onosproject.net.device.DeviceProviderService;
Aaron Kruglikov17b4c852016-01-15 16:37:04 -080051import org.onosproject.net.device.DeviceService;
Andrea Campanella7e6200a2016-03-21 09:48:40 -070052import org.onosproject.net.key.DeviceKey;
53import org.onosproject.net.key.DeviceKeyAdminService;
54import org.onosproject.net.key.DeviceKeyId;
Sanjay Se8dcfee2015-04-23 10:07:08 +053055import org.onosproject.net.provider.AbstractProvider;
56import org.onosproject.net.provider.ProviderId;
andreaeb70a942015-10-16 21:34:46 -070057import org.onosproject.netconf.NetconfController;
andreaeb70a942015-10-16 21:34:46 -070058import org.onosproject.netconf.NetconfDeviceListener;
Andrea Campanella8b1cb672016-01-25 13:58:58 -080059import org.onosproject.netconf.NetconfException;
Sanjay Se8dcfee2015-04-23 10:07:08 +053060import org.slf4j.Logger;
61
Andrea Campanella087ceb92015-12-07 09:58:34 -080062import java.io.IOException;
Andrea Campanella7e6200a2016-03-21 09:48:40 -070063import java.net.Socket;
64import java.net.URI;
65import java.net.URISyntaxException;
66import java.util.Arrays;
Andrea Campanella5c999e22016-03-01 15:12:53 -080067import java.util.concurrent.ExecutorService;
68import java.util.concurrent.Executors;
helenyrwufd296b62016-06-22 17:43:02 -070069import java.util.concurrent.ScheduledExecutorService;
70import java.util.concurrent.ScheduledFuture;
71import java.util.concurrent.TimeUnit;
andreaeb70a942015-10-16 21:34:46 -070072
Yuta HIGUCHI1624df12016-07-21 16:54:33 -070073import static java.util.concurrent.Executors.newScheduledThreadPool;
Andrea Campanella5c999e22016-03-01 15:12:53 -080074import static org.onlab.util.Tools.groupedThreads;
andreaeb70a942015-10-16 21:34:46 -070075import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
76import static org.slf4j.LoggerFactory.getLogger;
77
Sanjay Se8dcfee2015-04-23 10:07:08 +053078/**
andreaeb70a942015-10-16 21:34:46 -070079 * Provider which uses an NETCONF controller to detect device.
Sanjay Se8dcfee2015-04-23 10:07:08 +053080 */
81@Component(immediate = true)
82public class NetconfDeviceProvider extends AbstractProvider
83 implements DeviceProvider {
Andrea Campanella7e6200a2016-03-21 09:48:40 -070084
andreaeb70a942015-10-16 21:34:46 -070085 private final Logger log = getLogger(getClass());
Sanjay Se8dcfee2015-04-23 10:07:08 +053086
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected DeviceProviderRegistry providerRegistry;
89
andreaeb70a942015-10-16 21:34:46 -070090 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanella101417d2015-12-11 17:58:07 -080091 protected NetconfController controller;
Sanjay Se8dcfee2015-04-23 10:07:08 +053092
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
andreaeb70a942015-10-16 21:34:46 -070094 protected NetworkConfigRegistry cfgService;
Sanjay Se8dcfee2015-04-23 10:07:08 +053095
Thomas Vachuskad6811712015-04-29 21:37:04 -070096 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
andreaeb70a942015-10-16 21:34:46 -070097 protected CoreService coreService;
Thomas Vachuskad6811712015-04-29 21:37:04 -070098
Aaron Kruglikov17b4c852016-01-15 16:37:04 -080099 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700100 protected DeviceService deviceService;
Aaron Kruglikov17b4c852016-01-15 16:37:04 -0800101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700103 protected DeviceKeyAdminService deviceKeyAdminService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected MastershipService mastershipService;
107
Michele Santuari576f09c2016-09-28 14:20:00 +0200108 protected static final String APP_NAME = "org.onosproject.netconf";
Andrea Campanella101417d2015-12-11 17:58:07 -0800109 private static final String SCHEME_NAME = "netconf";
110 private static final String DEVICE_PROVIDER_PACKAGE = "org.onosproject.netconf.provider.device";
111 private static final String UNKNOWN = "unknown";
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700112 protected static final String ISNULL = "NetconfDeviceInfo is null";
113 private static final String IPADDRESS = "ipaddress";
114 private static final String NETCONF = "netconf";
115 private static final String PORT = "port";
helenyrwufd296b62016-06-22 17:43:02 -0700116 private static final int CORE_POOL_SIZE = 10;
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700117 //FIXME eventually a property
118 private static final int ISREACHABLE_TIMEOUT = 2000;
helenyrwufd296b62016-06-22 17:43:02 -0700119 private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 30;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530120
Michele Santuari576f09c2016-09-28 14:20:00 +0200121 protected final ExecutorService executor =
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700122 Executors.newFixedThreadPool(5, groupedThreads("onos/netconfdeviceprovider",
123 "device-installer-%d", log));
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700124 protected ScheduledExecutorService connectionExecutor
125 = newScheduledThreadPool(CORE_POOL_SIZE,
126 groupedThreads("onos/netconfdeviceprovider",
127 "connection-executor-%d", log));
Andrea Campanella5c999e22016-03-01 15:12:53 -0800128
Michele Santuari576f09c2016-09-28 14:20:00 +0200129 protected DeviceProviderService providerService;
andreaeb70a942015-10-16 21:34:46 -0700130 private NetconfDeviceListener innerNodeListener = new InnerNetconfDeviceListener();
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700131 private InternalDeviceListener deviceListener = new InternalDeviceListener();
Michele Santuari576f09c2016-09-28 14:20:00 +0200132 protected ScheduledFuture<?> scheduledTask;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530133
andreaeb70a942015-10-16 21:34:46 -0700134 private final ConfigFactory factory =
135 new ConfigFactory<ApplicationId, NetconfProviderConfig>(APP_SUBJECT_FACTORY,
136 NetconfProviderConfig.class,
137 "devices",
138 true) {
139 @Override
140 public NetconfProviderConfig createConfig() {
141 return new NetconfProviderConfig();
142 }
143 };
Michele Santuari576f09c2016-09-28 14:20:00 +0200144 protected final NetworkConfigListener cfgListener = new InternalNetworkConfigListener();
andreaeb70a942015-10-16 21:34:46 -0700145 private ApplicationId appId;
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700146 private boolean active;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530147
Sanjay Se8dcfee2015-04-23 10:07:08 +0530148
149 @Activate
andreaeb70a942015-10-16 21:34:46 -0700150 public void activate() {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700151 active = true;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530152 providerService = providerRegistry.register(this);
Andrea Campanella101417d2015-12-11 17:58:07 -0800153 appId = coreService.registerApplication(APP_NAME);
andreaeb70a942015-10-16 21:34:46 -0700154 cfgService.registerConfigFactory(factory);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700155 cfgService.addListener(cfgListener);
andreaeb70a942015-10-16 21:34:46 -0700156 controller.addDeviceListener(innerNodeListener);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700157 deviceService.addListener(deviceListener);
Andrea Campanella7d8449b2016-03-02 10:16:42 -0800158 executor.execute(NetconfDeviceProvider.this::connectDevices);
helenyrwufd296b62016-06-22 17:43:02 -0700159 scheduledTask = schedulePolling();
Thomas Vachuskad6811712015-04-29 21:37:04 -0700160 log.info("Started");
Sanjay Se8dcfee2015-04-23 10:07:08 +0530161 }
162
andreaeb70a942015-10-16 21:34:46 -0700163
Sanjay Se8dcfee2015-04-23 10:07:08 +0530164 @Deactivate
andreaeb70a942015-10-16 21:34:46 -0700165 public void deactivate() {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700166 deviceService.removeListener(deviceListener);
167 active = false;
168 controller.getNetconfDevices().forEach(id -> {
169 deviceKeyAdminService.removeKey(DeviceKeyId.deviceKeyId(id.toString()));
170 controller.disconnectDevice(id, true);
171 });
Andrea Campanella86294db2016-03-07 11:42:49 -0800172 controller.removeDeviceListener(innerNodeListener);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700173 deviceService.removeListener(deviceListener);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530174 providerRegistry.unregister(this);
175 providerService = null;
andreaeb70a942015-10-16 21:34:46 -0700176 cfgService.unregisterConfigFactory(factory);
helenyrwufd296b62016-06-22 17:43:02 -0700177 scheduledTask.cancel(true);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700178 executor.shutdown();
Sanjay Seb5eebb2015-04-24 15:44:50 +0530179 log.info("Stopped");
Sanjay Se8dcfee2015-04-23 10:07:08 +0530180 }
181
andreaeb70a942015-10-16 21:34:46 -0700182 public NetconfDeviceProvider() {
Andrea Campanella101417d2015-12-11 17:58:07 -0800183 super(new ProviderId(SCHEME_NAME, DEVICE_PROVIDER_PACKAGE));
Sanjay Se8dcfee2015-04-23 10:07:08 +0530184 }
185
helenyrwufd296b62016-06-22 17:43:02 -0700186 // Checks connection to devices in the config file
187 // every DEFAULT_POLL_FREQUENCY_SECONDS seconds.
188 private ScheduledFuture schedulePolling() {
Yuta HIGUCHIc2b82e32017-03-10 14:33:41 -0800189 return connectionExecutor.scheduleAtFixedRate(exceptionSafe(this::checkAndUpdateDevices),
helenyrwufd296b62016-06-22 17:43:02 -0700190 DEFAULT_POLL_FREQUENCY_SECONDS / 10,
191 DEFAULT_POLL_FREQUENCY_SECONDS,
192 TimeUnit.SECONDS);
193 }
194
Yuta HIGUCHIc2b82e32017-03-10 14:33:41 -0800195 private Runnable exceptionSafe(Runnable runnable) {
196 return new Runnable() {
197
198 @Override
199 public void run() {
200 try {
201 runnable.run();
202 } catch (Exception e) {
203 log.error("Unhandled Exception", e);
204 }
205 }
206 };
207 }
208
Sanjay Se8dcfee2015-04-23 10:07:08 +0530209 @Override
210 public void triggerProbe(DeviceId deviceId) {
andreaeb70a942015-10-16 21:34:46 -0700211 // TODO: This will be implemented later.
212 log.info("Triggering probe on device {}", deviceId);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530213 }
214
215 @Override
216 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700217 if (active) {
218 switch (newRole) {
219 case MASTER:
220 initiateConnection(deviceId, newRole);
221 log.debug("Accepting mastership role change to {} for device {}", newRole, deviceId);
222 break;
223 case STANDBY:
224 controller.disconnectDevice(deviceId, false);
225 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.STANDBY);
226 //else no-op
227 break;
228 case NONE:
229 controller.disconnectDevice(deviceId, false);
230 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.NONE);
231 break;
232 default:
233 log.error("Unimplemented Mastership state : {}", newRole);
234
235 }
236 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530237 }
238
239 @Override
240 public boolean isReachable(DeviceId deviceId) {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700241 //FIXME this is a workaround util device state is shared
242 // between controller instances.
243 Device device = deviceService.getDevice(deviceId);
244 String ip;
245 int port;
246 Socket socket = null;
247 if (device != null) {
248 ip = device.annotations().value(IPADDRESS);
249 port = Integer.parseInt(device.annotations().value(PORT));
250 } else {
251 String[] info = deviceId.toString().split(":");
252 if (info.length == 3) {
253 ip = info[1];
254 port = Integer.parseInt(info[2]);
255 } else {
256 ip = Arrays.asList(info).stream().filter(el -> !el.equals(info[0])
257 && !el.equals(info[info.length - 1]))
258 .reduce((t, u) -> t + ":" + u)
259 .get();
260 log.debug("ip v6 {}", ip);
261 port = Integer.parseInt(info[info.length - 1]);
262 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530263 }
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700264 //test connection to device opening a socket to it.
265 try {
266 socket = new Socket(ip, port);
267 log.debug("rechability of {}, {}, {}", deviceId, socket.isConnected() && !socket.isClosed());
268 return socket.isConnected() && !socket.isClosed();
269 } catch (IOException e) {
270 log.info("Device {} is not reachable", deviceId);
271 return false;
272 } finally {
273 if (socket != null) {
274 try {
275 socket.close();
276 } catch (IOException e) {
277 log.debug("Test Socket failed {} ", deviceId);
278 return false;
279 }
280 }
281 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530282 }
283
Saurav Dasa2d37502016-03-25 17:50:40 -0700284 @Override
285 public void changePortState(DeviceId deviceId, PortNumber portNumber,
286 boolean enable) {
287 // TODO if required
288 }
289
andreaeb70a942015-10-16 21:34:46 -0700290 private class InnerNetconfDeviceListener implements NetconfDeviceListener {
Sanjay Se8dcfee2015-04-23 10:07:08 +0530291
Andrea Campanella101417d2015-12-11 17:58:07 -0800292
andreaeb70a942015-10-16 21:34:46 -0700293 @Override
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700294 public void deviceAdded(DeviceId deviceId) {
295 //no-op
296 log.debug("Netconf device {} added to Netconf subController", deviceId);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530297 }
298
299 @Override
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700300 public void deviceRemoved(DeviceId deviceId) {
301 Preconditions.checkNotNull(deviceId, ISNULL);
helenyrwufd296b62016-06-22 17:43:02 -0700302
303 if (deviceService.getDevice(deviceId) != null) {
304 providerService.deviceDisconnected(deviceId);
305 log.debug("Netconf device {} removed from Netconf subController", deviceId);
306 } else {
307 log.warn("Netconf device {} does not exist in the store, " +
308 "it may already have been removed", deviceId);
309 }
andreaeb70a942015-10-16 21:34:46 -0700310 }
311 }
312
andreaeb70a942015-10-16 21:34:46 -0700313 private void connectDevices() {
314 NetconfProviderConfig cfg = cfgService.getConfig(appId, NetconfProviderConfig.class);
315 if (cfg != null) {
Sanjay Se8dcfee2015-04-23 10:07:08 +0530316 try {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700317 cfg.getDevicesAddresses().forEach(addr -> {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700318 DeviceId deviceId = getDeviceId(addr.ip().toString(), addr.port());
319 Preconditions.checkNotNull(deviceId, ISNULL);
320 //Netconf configuration object
321 ChassisId cid = new ChassisId();
322 String ipAddress = addr.ip().toString();
323 SparseAnnotations annotations = DefaultAnnotations.builder()
324 .set(IPADDRESS, ipAddress)
325 .set(PORT, String.valueOf(addr.port()))
326 .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase())
327 .build();
328 DeviceDescription deviceDescription = new DefaultDeviceDescription(
329 deviceId.uri(),
330 Device.Type.SWITCH,
331 UNKNOWN, UNKNOWN,
332 UNKNOWN, UNKNOWN,
helenyrwufd296b62016-06-22 17:43:02 -0700333 cid, false,
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700334 annotations);
Himanshu Ranjan7c2ee3c2017-02-13 05:10:08 -0600335 storeDeviceKey(addr, deviceId);
336
helenyrwufd296b62016-06-22 17:43:02 -0700337 if (deviceService.getDevice(deviceId) == null) {
338 providerService.deviceConnected(deviceId, deviceDescription);
339 }
Yuta HIGUCHIc2b82e32017-03-10 14:33:41 -0800340 try {
341 checkAndUpdateDevice(deviceId, deviceDescription);
342 } catch (Exception e) {
343 log.error("Unhandled exception checking {}", deviceId, e);
344 }
helenyrwufd296b62016-06-22 17:43:02 -0700345 });
346 } catch (ConfigException e) {
347 log.error("Cannot read config error " + e);
348 }
349 }
350 }
351
352 private void checkAndUpdateDevice(DeviceId deviceId, DeviceDescription deviceDescription) {
353 if (deviceService.getDevice(deviceId) == null) {
354 log.warn("Device {} has not been added to store, " +
355 "maybe due to a problem in connectivity", deviceId);
356 } else {
357 boolean isReachable = isReachable(deviceId);
358 if (isReachable && !deviceService.isAvailable(deviceId)) {
Konstantinos Kanonakis4d67dd82016-08-05 12:18:52 -0500359 Device device = deviceService.getDevice(deviceId);
Konstantinos Kanonakis4d67dd82016-08-05 12:18:52 -0500360 if (device.is(DeviceDescriptionDiscovery.class)) {
361 if (mastershipService.isLocalMaster(deviceId)) {
362 DeviceDescriptionDiscovery deviceDescriptionDiscovery =
363 device.as(DeviceDescriptionDiscovery.class);
Michele Santuari00cc1f72016-09-08 17:05:24 +0200364 DeviceDescription updatedDeviceDescription = deviceDescriptionDiscovery.discoverDeviceDetails();
365 if (updatedDeviceDescription != null &&
366 !descriptionEquals(device, updatedDeviceDescription)) {
367 providerService.deviceConnected(
368 deviceId, new DefaultDeviceDescription(
369 updatedDeviceDescription, true, updatedDeviceDescription.annotations()));
Michele Santuari576f09c2016-09-28 14:20:00 +0200370 } else if (updatedDeviceDescription == null) {
371 providerService.deviceConnected(
372 deviceId, new DefaultDeviceDescription(
373 deviceDescription, true, deviceDescription.annotations()));
Michele Santuari00cc1f72016-09-08 17:05:24 +0200374 }
375 //if ports are not discovered, retry the discovery
376 if (deviceService.getPorts(deviceId).isEmpty()) {
377 discoverPorts(deviceId);
378 }
Konstantinos Kanonakis4d67dd82016-08-05 12:18:52 -0500379 }
380 } else {
Michele Santuari576f09c2016-09-28 14:20:00 +0200381 log.warn("No DeviceDescriptionDiscovery behaviour for device {} " +
382 "using DefaultDeviceDescription", deviceId);
383 providerService.deviceConnected(
384 deviceId, new DefaultDeviceDescription(
385 deviceDescription, true, deviceDescription.annotations()));
Konstantinos Kanonakis4d67dd82016-08-05 12:18:52 -0500386 }
helenyrwufd296b62016-06-22 17:43:02 -0700387 } else if (!isReachable && deviceService.isAvailable(deviceId)) {
388 providerService.deviceDisconnected(deviceId);
389 }
390 }
391 }
392
Michele Santuari00cc1f72016-09-08 17:05:24 +0200393 private boolean descriptionEquals(Device device, DeviceDescription updatedDeviceDescription) {
Yuta HIGUCHIf381fc72017-01-03 10:39:36 -0800394 return Objects.equal(device.id().uri(), updatedDeviceDescription.deviceUri())
Michele Santuari00cc1f72016-09-08 17:05:24 +0200395 && Objects.equal(device.type(), updatedDeviceDescription.type())
396 && Objects.equal(device.manufacturer(), updatedDeviceDescription.manufacturer())
397 && Objects.equal(device.hwVersion(), updatedDeviceDescription.hwVersion())
398 && Objects.equal(device.swVersion(), updatedDeviceDescription.swVersion())
399 && Objects.equal(device.serialNumber(), updatedDeviceDescription.serialNumber())
400 && Objects.equal(device.chassisId(), updatedDeviceDescription.chassisId())
401 && Objects.equal(device.annotations(), updatedDeviceDescription.annotations());
402 }
403
helenyrwufd296b62016-06-22 17:43:02 -0700404 private void checkAndUpdateDevices() {
405 NetconfProviderConfig cfg = cfgService.getConfig(appId, NetconfProviderConfig.class);
406 if (cfg != null) {
407 log.info("Checking connection to devices in configuration");
408 try {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700409 cfg.getDevicesAddresses().forEach(addr -> {
helenyrwufd296b62016-06-22 17:43:02 -0700410 DeviceId deviceId = getDeviceId(addr.ip().toString(), addr.port());
411 Preconditions.checkNotNull(deviceId, ISNULL);
412 //Netconf configuration object
413 ChassisId cid = new ChassisId();
414 String ipAddress = addr.ip().toString();
415 SparseAnnotations annotations = DefaultAnnotations.builder()
416 .set(IPADDRESS, ipAddress)
417 .set(PORT, String.valueOf(addr.port()))
418 .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase())
419 .build();
420 DeviceDescription deviceDescription = new DefaultDeviceDescription(
421 deviceId.uri(),
422 Device.Type.SWITCH,
423 UNKNOWN, UNKNOWN,
424 UNKNOWN, UNKNOWN,
425 cid, false,
426 annotations);
Himanshu Ranjan7c2ee3c2017-02-13 05:10:08 -0600427 storeDeviceKey(addr, deviceId);
helenyrwufd296b62016-06-22 17:43:02 -0700428 checkAndUpdateDevice(deviceId, deviceDescription);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700429 });
andreaeb70a942015-10-16 21:34:46 -0700430 } catch (ConfigException e) {
431 log.error("Cannot read config error " + e);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530432 }
433 }
andreaeb70a942015-10-16 21:34:46 -0700434 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530435
Himanshu Ranjan7c2ee3c2017-02-13 05:10:08 -0600436 private void storeDeviceKey(NetconfProviderConfig.NetconfDeviceAddress addr, DeviceId deviceId) {
437 if (addr.sshkey().equals("")) {
438 deviceKeyAdminService.addKey(
439 DeviceKey.createDeviceKeyUsingUsernamePassword(
440 DeviceKeyId.deviceKeyId(deviceId.toString()),
441 null, addr.name(), addr.password()));
442 } else {
443 deviceKeyAdminService.addKey(
444 DeviceKey.createDeviceKeyUsingSshKey(
445 DeviceKeyId.deviceKeyId(deviceId.toString()),
446 null, addr.name(), addr.password(), addr.sshkey()));
447 }
448 }
449
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700450 private void initiateConnection(DeviceId deviceId, MastershipRole newRole) {
451 try {
452 if (isReachable(deviceId)) {
453 controller.connectDevice(deviceId);
454 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.MASTER);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700455 }
456 } catch (Exception e) {
457 if (deviceService.getDevice(deviceId) != null) {
458 providerService.deviceDisconnected(deviceId);
459 }
460 deviceKeyAdminService.removeKey(DeviceKeyId.deviceKeyId(deviceId.toString()));
461 throw new RuntimeException(new NetconfException(
462 "Can't connect to NETCONF " + "device on " + deviceId + ":" + deviceId, e));
463
464 }
465 }
466
467 private void discoverPorts(DeviceId deviceId) {
468 Device device = deviceService.getDevice(deviceId);
Andrea Campanella6c71a052016-04-22 11:56:31 -0700469 //TODO remove when PortDiscovery is removed from master
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700470 if (device.is(PortDiscovery.class)) {
471 PortDiscovery portConfig = device.as(PortDiscovery.class);
472 providerService.updatePorts(deviceId,
473 portConfig.getPorts());
Andrea Campanella6c71a052016-04-22 11:56:31 -0700474 } else if (device.is(DeviceDescriptionDiscovery.class)) {
475 DeviceDescriptionDiscovery deviceDescriptionDiscovery =
476 device.as(DeviceDescriptionDiscovery.class);
477 providerService.updatePorts(deviceId,
478 deviceDescriptionDiscovery.discoverPortDetails());
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700479 } else {
480 log.warn("No portGetter behaviour for device {}", deviceId);
481 }
482 }
483
484 /**
485 * Return the DeviceId about the device containing the URI.
486 *
Andrea Campanella6c71a052016-04-22 11:56:31 -0700487 * @param ip IP address
Ray Milkeyd4334db2016-04-05 17:39:44 -0700488 * @param port port number
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700489 * @return DeviceId
490 */
491 public DeviceId getDeviceId(String ip, int port) {
492 try {
493 return DeviceId.deviceId(new URI(NETCONF, ip + ":" + port, null));
494 } catch (URISyntaxException e) {
495 throw new IllegalArgumentException("Unable to build deviceID for device "
496 + ip + ":" + port, e);
497 }
498 }
499
500 /**
501 * Listener for configuration events.
502 */
andreaeb70a942015-10-16 21:34:46 -0700503 private class InternalNetworkConfigListener implements NetworkConfigListener {
Sanjay Se8dcfee2015-04-23 10:07:08 +0530504
andreaeb70a942015-10-16 21:34:46 -0700505
506 @Override
507 public void event(NetworkConfigEvent event) {
Andrea Campanella90f044f2016-03-02 09:14:57 -0800508 executor.execute(NetconfDeviceProvider.this::connectDevices);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530509 }
510
andreaeb70a942015-10-16 21:34:46 -0700511 @Override
512 public boolean isRelevant(NetworkConfigEvent event) {
andreaeb70a942015-10-16 21:34:46 -0700513 return event.configClass().equals(NetconfProviderConfig.class) &&
514 (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
515 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530516 }
517 }
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700518
519 /**
520 * Listener for core device events.
521 */
522 private class InternalDeviceListener implements DeviceListener {
523 @Override
524 public void event(DeviceEvent event) {
525 if ((event.type() == DeviceEvent.Type.DEVICE_ADDED)) {
526 executor.execute(() -> discoverPorts(event.subject().id()));
527 } else if ((event.type() == DeviceEvent.Type.DEVICE_REMOVED)) {
528 log.debug("removing device {}", event.subject().id());
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700529 controller.disconnectDevice(event.subject().id(), true);
530 }
531 }
532
533 @Override
534 public boolean isRelevant(DeviceEvent event) {
535 if (mastershipService.getMasterFor(event.subject().id()) == null) {
536 return true;
537 }
538 return event.subject().annotations().value(AnnotationKeys.PROTOCOL)
539 .equals(SCHEME_NAME.toUpperCase()) &&
Michele Santuari576f09c2016-09-28 14:20:00 +0200540 mastershipService.isLocalMaster(event.subject().id());
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700541 }
542 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530543}