blob: 1720e2eda00f5e72c77a565ff45fb6e16cb624cf [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;
Gaurav Agrawaldab4d772017-03-29 15:15:13 +053052import org.onosproject.net.device.PortStatisticsDiscovery;
Andrea Campanella7e6200a2016-03-21 09:48:40 -070053import org.onosproject.net.key.DeviceKey;
54import org.onosproject.net.key.DeviceKeyAdminService;
55import org.onosproject.net.key.DeviceKeyId;
Sanjay Se8dcfee2015-04-23 10:07:08 +053056import org.onosproject.net.provider.AbstractProvider;
57import org.onosproject.net.provider.ProviderId;
andreaeb70a942015-10-16 21:34:46 -070058import org.onosproject.netconf.NetconfController;
andreaeb70a942015-10-16 21:34:46 -070059import org.onosproject.netconf.NetconfDeviceListener;
Andrea Campanella8b1cb672016-01-25 13:58:58 -080060import org.onosproject.netconf.NetconfException;
Sanjay Se8dcfee2015-04-23 10:07:08 +053061import org.slf4j.Logger;
62
Andrea Campanella087ceb92015-12-07 09:58:34 -080063import java.io.IOException;
Andrea Campanella7e6200a2016-03-21 09:48:40 -070064import java.net.Socket;
65import java.net.URI;
66import java.net.URISyntaxException;
67import java.util.Arrays;
Andrea Campanella5c999e22016-03-01 15:12:53 -080068import java.util.concurrent.ExecutorService;
69import java.util.concurrent.Executors;
helenyrwufd296b62016-06-22 17:43:02 -070070import java.util.concurrent.ScheduledExecutorService;
71import java.util.concurrent.ScheduledFuture;
72import java.util.concurrent.TimeUnit;
andreaeb70a942015-10-16 21:34:46 -070073
Yuta HIGUCHI1624df12016-07-21 16:54:33 -070074import static java.util.concurrent.Executors.newScheduledThreadPool;
Andrea Campanella5c999e22016-03-01 15:12:53 -080075import static org.onlab.util.Tools.groupedThreads;
andreaeb70a942015-10-16 21:34:46 -070076import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
77import static org.slf4j.LoggerFactory.getLogger;
78
Sanjay Se8dcfee2015-04-23 10:07:08 +053079/**
andreaeb70a942015-10-16 21:34:46 -070080 * Provider which uses an NETCONF controller to detect device.
Sanjay Se8dcfee2015-04-23 10:07:08 +053081 */
82@Component(immediate = true)
83public class NetconfDeviceProvider extends AbstractProvider
84 implements DeviceProvider {
Andrea Campanella7e6200a2016-03-21 09:48:40 -070085
andreaeb70a942015-10-16 21:34:46 -070086 private final Logger log = getLogger(getClass());
Sanjay Se8dcfee2015-04-23 10:07:08 +053087
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected DeviceProviderRegistry providerRegistry;
90
andreaeb70a942015-10-16 21:34:46 -070091 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanella101417d2015-12-11 17:58:07 -080092 protected NetconfController controller;
Sanjay Se8dcfee2015-04-23 10:07:08 +053093
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
andreaeb70a942015-10-16 21:34:46 -070095 protected NetworkConfigRegistry cfgService;
Sanjay Se8dcfee2015-04-23 10:07:08 +053096
Thomas Vachuskad6811712015-04-29 21:37:04 -070097 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
andreaeb70a942015-10-16 21:34:46 -070098 protected CoreService coreService;
Thomas Vachuskad6811712015-04-29 21:37:04 -070099
Aaron Kruglikov17b4c852016-01-15 16:37:04 -0800100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700101 protected DeviceService deviceService;
Aaron Kruglikov17b4c852016-01-15 16:37:04 -0800102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700104 protected DeviceKeyAdminService deviceKeyAdminService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected MastershipService mastershipService;
108
Michele Santuari576f09c2016-09-28 14:20:00 +0200109 protected static final String APP_NAME = "org.onosproject.netconf";
Andrea Campanella101417d2015-12-11 17:58:07 -0800110 private static final String SCHEME_NAME = "netconf";
111 private static final String DEVICE_PROVIDER_PACKAGE = "org.onosproject.netconf.provider.device";
112 private static final String UNKNOWN = "unknown";
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700113 protected static final String ISNULL = "NetconfDeviceInfo is null";
114 private static final String IPADDRESS = "ipaddress";
115 private static final String NETCONF = "netconf";
116 private static final String PORT = "port";
helenyrwufd296b62016-06-22 17:43:02 -0700117 private static final int CORE_POOL_SIZE = 10;
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700118 //FIXME eventually a property
119 private static final int ISREACHABLE_TIMEOUT = 2000;
helenyrwufd296b62016-06-22 17:43:02 -0700120 private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 30;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530121
Michele Santuari576f09c2016-09-28 14:20:00 +0200122 protected final ExecutorService executor =
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700123 Executors.newFixedThreadPool(5, groupedThreads("onos/netconfdeviceprovider",
124 "device-installer-%d", log));
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700125 protected ScheduledExecutorService connectionExecutor
126 = newScheduledThreadPool(CORE_POOL_SIZE,
127 groupedThreads("onos/netconfdeviceprovider",
128 "connection-executor-%d", log));
Andrea Campanella5c999e22016-03-01 15:12:53 -0800129
Michele Santuari576f09c2016-09-28 14:20:00 +0200130 protected DeviceProviderService providerService;
andreaeb70a942015-10-16 21:34:46 -0700131 private NetconfDeviceListener innerNodeListener = new InnerNetconfDeviceListener();
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700132 private InternalDeviceListener deviceListener = new InternalDeviceListener();
Michele Santuari576f09c2016-09-28 14:20:00 +0200133 protected ScheduledFuture<?> scheduledTask;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530134
andreaeb70a942015-10-16 21:34:46 -0700135 private final ConfigFactory factory =
136 new ConfigFactory<ApplicationId, NetconfProviderConfig>(APP_SUBJECT_FACTORY,
137 NetconfProviderConfig.class,
138 "devices",
139 true) {
140 @Override
141 public NetconfProviderConfig createConfig() {
142 return new NetconfProviderConfig();
143 }
144 };
Michele Santuari576f09c2016-09-28 14:20:00 +0200145 protected final NetworkConfigListener cfgListener = new InternalNetworkConfigListener();
andreaeb70a942015-10-16 21:34:46 -0700146 private ApplicationId appId;
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700147 private boolean active;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530148
Sanjay Se8dcfee2015-04-23 10:07:08 +0530149
150 @Activate
andreaeb70a942015-10-16 21:34:46 -0700151 public void activate() {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700152 active = true;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530153 providerService = providerRegistry.register(this);
Andrea Campanella101417d2015-12-11 17:58:07 -0800154 appId = coreService.registerApplication(APP_NAME);
andreaeb70a942015-10-16 21:34:46 -0700155 cfgService.registerConfigFactory(factory);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700156 cfgService.addListener(cfgListener);
andreaeb70a942015-10-16 21:34:46 -0700157 controller.addDeviceListener(innerNodeListener);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700158 deviceService.addListener(deviceListener);
Andrea Campanella7d8449b2016-03-02 10:16:42 -0800159 executor.execute(NetconfDeviceProvider.this::connectDevices);
helenyrwufd296b62016-06-22 17:43:02 -0700160 scheduledTask = schedulePolling();
Thomas Vachuskad6811712015-04-29 21:37:04 -0700161 log.info("Started");
Sanjay Se8dcfee2015-04-23 10:07:08 +0530162 }
163
andreaeb70a942015-10-16 21:34:46 -0700164
Sanjay Se8dcfee2015-04-23 10:07:08 +0530165 @Deactivate
andreaeb70a942015-10-16 21:34:46 -0700166 public void deactivate() {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700167 deviceService.removeListener(deviceListener);
168 active = false;
169 controller.getNetconfDevices().forEach(id -> {
170 deviceKeyAdminService.removeKey(DeviceKeyId.deviceKeyId(id.toString()));
171 controller.disconnectDevice(id, true);
172 });
Andrea Campanella86294db2016-03-07 11:42:49 -0800173 controller.removeDeviceListener(innerNodeListener);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700174 deviceService.removeListener(deviceListener);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530175 providerRegistry.unregister(this);
176 providerService = null;
andreaeb70a942015-10-16 21:34:46 -0700177 cfgService.unregisterConfigFactory(factory);
helenyrwufd296b62016-06-22 17:43:02 -0700178 scheduledTask.cancel(true);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700179 executor.shutdown();
Sanjay Seb5eebb2015-04-24 15:44:50 +0530180 log.info("Stopped");
Sanjay Se8dcfee2015-04-23 10:07:08 +0530181 }
182
andreaeb70a942015-10-16 21:34:46 -0700183 public NetconfDeviceProvider() {
Andrea Campanella101417d2015-12-11 17:58:07 -0800184 super(new ProviderId(SCHEME_NAME, DEVICE_PROVIDER_PACKAGE));
Sanjay Se8dcfee2015-04-23 10:07:08 +0530185 }
186
helenyrwufd296b62016-06-22 17:43:02 -0700187 // Checks connection to devices in the config file
188 // every DEFAULT_POLL_FREQUENCY_SECONDS seconds.
189 private ScheduledFuture schedulePolling() {
Yuta HIGUCHIc2b82e32017-03-10 14:33:41 -0800190 return connectionExecutor.scheduleAtFixedRate(exceptionSafe(this::checkAndUpdateDevices),
helenyrwufd296b62016-06-22 17:43:02 -0700191 DEFAULT_POLL_FREQUENCY_SECONDS / 10,
192 DEFAULT_POLL_FREQUENCY_SECONDS,
193 TimeUnit.SECONDS);
194 }
195
Yuta HIGUCHIc2b82e32017-03-10 14:33:41 -0800196 private Runnable exceptionSafe(Runnable runnable) {
197 return new Runnable() {
198
199 @Override
200 public void run() {
201 try {
202 runnable.run();
203 } catch (Exception e) {
204 log.error("Unhandled Exception", e);
205 }
206 }
207 };
208 }
209
Sanjay Se8dcfee2015-04-23 10:07:08 +0530210 @Override
211 public void triggerProbe(DeviceId deviceId) {
andreaeb70a942015-10-16 21:34:46 -0700212 // TODO: This will be implemented later.
213 log.info("Triggering probe on device {}", deviceId);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530214 }
215
216 @Override
217 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700218 if (active) {
219 switch (newRole) {
220 case MASTER:
221 initiateConnection(deviceId, newRole);
222 log.debug("Accepting mastership role change to {} for device {}", newRole, deviceId);
223 break;
224 case STANDBY:
225 controller.disconnectDevice(deviceId, false);
226 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.STANDBY);
227 //else no-op
228 break;
229 case NONE:
230 controller.disconnectDevice(deviceId, false);
231 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.NONE);
232 break;
233 default:
234 log.error("Unimplemented Mastership state : {}", newRole);
235
236 }
237 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530238 }
239
240 @Override
241 public boolean isReachable(DeviceId deviceId) {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700242 //FIXME this is a workaround util device state is shared
243 // between controller instances.
244 Device device = deviceService.getDevice(deviceId);
245 String ip;
246 int port;
247 Socket socket = null;
248 if (device != null) {
249 ip = device.annotations().value(IPADDRESS);
250 port = Integer.parseInt(device.annotations().value(PORT));
251 } else {
252 String[] info = deviceId.toString().split(":");
253 if (info.length == 3) {
254 ip = info[1];
255 port = Integer.parseInt(info[2]);
256 } else {
257 ip = Arrays.asList(info).stream().filter(el -> !el.equals(info[0])
258 && !el.equals(info[info.length - 1]))
259 .reduce((t, u) -> t + ":" + u)
260 .get();
261 log.debug("ip v6 {}", ip);
262 port = Integer.parseInt(info[info.length - 1]);
263 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530264 }
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700265 //test connection to device opening a socket to it.
266 try {
267 socket = new Socket(ip, port);
Yuta HIGUCHI0454d702017-03-17 10:08:38 -0700268 log.debug("rechability of {}, {}, {}", deviceId, socket.isConnected(), !socket.isClosed());
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700269 return socket.isConnected() && !socket.isClosed();
270 } catch (IOException e) {
271 log.info("Device {} is not reachable", deviceId);
272 return false;
273 } finally {
274 if (socket != null) {
275 try {
276 socket.close();
277 } catch (IOException e) {
278 log.debug("Test Socket failed {} ", deviceId);
279 return false;
280 }
281 }
282 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530283 }
284
Saurav Dasa2d37502016-03-25 17:50:40 -0700285 @Override
286 public void changePortState(DeviceId deviceId, PortNumber portNumber,
287 boolean enable) {
288 // TODO if required
289 }
290
andreaeb70a942015-10-16 21:34:46 -0700291 private class InnerNetconfDeviceListener implements NetconfDeviceListener {
Sanjay Se8dcfee2015-04-23 10:07:08 +0530292
Andrea Campanella101417d2015-12-11 17:58:07 -0800293
andreaeb70a942015-10-16 21:34:46 -0700294 @Override
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700295 public void deviceAdded(DeviceId deviceId) {
296 //no-op
297 log.debug("Netconf device {} added to Netconf subController", deviceId);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530298 }
299
300 @Override
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700301 public void deviceRemoved(DeviceId deviceId) {
302 Preconditions.checkNotNull(deviceId, ISNULL);
helenyrwufd296b62016-06-22 17:43:02 -0700303
304 if (deviceService.getDevice(deviceId) != null) {
305 providerService.deviceDisconnected(deviceId);
306 log.debug("Netconf device {} removed from Netconf subController", deviceId);
307 } else {
308 log.warn("Netconf device {} does not exist in the store, " +
309 "it may already have been removed", deviceId);
310 }
andreaeb70a942015-10-16 21:34:46 -0700311 }
312 }
313
andreaeb70a942015-10-16 21:34:46 -0700314 private void connectDevices() {
315 NetconfProviderConfig cfg = cfgService.getConfig(appId, NetconfProviderConfig.class);
316 if (cfg != null) {
Sanjay Se8dcfee2015-04-23 10:07:08 +0530317 try {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700318 cfg.getDevicesAddresses().forEach(addr -> {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700319 DeviceId deviceId = getDeviceId(addr.ip().toString(), addr.port());
320 Preconditions.checkNotNull(deviceId, ISNULL);
321 //Netconf configuration object
322 ChassisId cid = new ChassisId();
323 String ipAddress = addr.ip().toString();
324 SparseAnnotations annotations = DefaultAnnotations.builder()
325 .set(IPADDRESS, ipAddress)
326 .set(PORT, String.valueOf(addr.port()))
327 .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase())
328 .build();
329 DeviceDescription deviceDescription = new DefaultDeviceDescription(
330 deviceId.uri(),
331 Device.Type.SWITCH,
332 UNKNOWN, UNKNOWN,
333 UNKNOWN, UNKNOWN,
helenyrwufd296b62016-06-22 17:43:02 -0700334 cid, false,
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700335 annotations);
Himanshu Ranjan7c2ee3c2017-02-13 05:10:08 -0600336 storeDeviceKey(addr, deviceId);
337
helenyrwufd296b62016-06-22 17:43:02 -0700338 if (deviceService.getDevice(deviceId) == null) {
339 providerService.deviceConnected(deviceId, deviceDescription);
340 }
Yuta HIGUCHIc2b82e32017-03-10 14:33:41 -0800341 try {
342 checkAndUpdateDevice(deviceId, deviceDescription);
343 } catch (Exception e) {
344 log.error("Unhandled exception checking {}", deviceId, e);
345 }
helenyrwufd296b62016-06-22 17:43:02 -0700346 });
347 } catch (ConfigException e) {
348 log.error("Cannot read config error " + e);
349 }
350 }
351 }
352
353 private void checkAndUpdateDevice(DeviceId deviceId, DeviceDescription deviceDescription) {
354 if (deviceService.getDevice(deviceId) == null) {
355 log.warn("Device {} has not been added to store, " +
356 "maybe due to a problem in connectivity", deviceId);
357 } else {
358 boolean isReachable = isReachable(deviceId);
359 if (isReachable && !deviceService.isAvailable(deviceId)) {
Konstantinos Kanonakis4d67dd82016-08-05 12:18:52 -0500360 Device device = deviceService.getDevice(deviceId);
Konstantinos Kanonakis4d67dd82016-08-05 12:18:52 -0500361 if (device.is(DeviceDescriptionDiscovery.class)) {
362 if (mastershipService.isLocalMaster(deviceId)) {
363 DeviceDescriptionDiscovery deviceDescriptionDiscovery =
364 device.as(DeviceDescriptionDiscovery.class);
Michele Santuari00cc1f72016-09-08 17:05:24 +0200365 DeviceDescription updatedDeviceDescription = deviceDescriptionDiscovery.discoverDeviceDetails();
366 if (updatedDeviceDescription != null &&
367 !descriptionEquals(device, updatedDeviceDescription)) {
368 providerService.deviceConnected(
369 deviceId, new DefaultDeviceDescription(
370 updatedDeviceDescription, true, updatedDeviceDescription.annotations()));
Michele Santuari576f09c2016-09-28 14:20:00 +0200371 } else if (updatedDeviceDescription == null) {
372 providerService.deviceConnected(
373 deviceId, new DefaultDeviceDescription(
374 deviceDescription, true, deviceDescription.annotations()));
Michele Santuari00cc1f72016-09-08 17:05:24 +0200375 }
376 //if ports are not discovered, retry the discovery
377 if (deviceService.getPorts(deviceId).isEmpty()) {
378 discoverPorts(deviceId);
379 }
Konstantinos Kanonakis4d67dd82016-08-05 12:18:52 -0500380 }
381 } else {
Michele Santuari576f09c2016-09-28 14:20:00 +0200382 log.warn("No DeviceDescriptionDiscovery behaviour for device {} " +
383 "using DefaultDeviceDescription", deviceId);
384 providerService.deviceConnected(
385 deviceId, new DefaultDeviceDescription(
386 deviceDescription, true, deviceDescription.annotations()));
Konstantinos Kanonakis4d67dd82016-08-05 12:18:52 -0500387 }
helenyrwufd296b62016-06-22 17:43:02 -0700388 } else if (!isReachable && deviceService.isAvailable(deviceId)) {
389 providerService.deviceDisconnected(deviceId);
390 }
391 }
392 }
393
Michele Santuari00cc1f72016-09-08 17:05:24 +0200394 private boolean descriptionEquals(Device device, DeviceDescription updatedDeviceDescription) {
Yuta HIGUCHIf381fc72017-01-03 10:39:36 -0800395 return Objects.equal(device.id().uri(), updatedDeviceDescription.deviceUri())
Michele Santuari00cc1f72016-09-08 17:05:24 +0200396 && Objects.equal(device.type(), updatedDeviceDescription.type())
397 && Objects.equal(device.manufacturer(), updatedDeviceDescription.manufacturer())
398 && Objects.equal(device.hwVersion(), updatedDeviceDescription.hwVersion())
399 && Objects.equal(device.swVersion(), updatedDeviceDescription.swVersion())
400 && Objects.equal(device.serialNumber(), updatedDeviceDescription.serialNumber())
401 && Objects.equal(device.chassisId(), updatedDeviceDescription.chassisId())
402 && Objects.equal(device.annotations(), updatedDeviceDescription.annotations());
403 }
404
helenyrwufd296b62016-06-22 17:43:02 -0700405 private void checkAndUpdateDevices() {
406 NetconfProviderConfig cfg = cfgService.getConfig(appId, NetconfProviderConfig.class);
407 if (cfg != null) {
408 log.info("Checking connection to devices in configuration");
409 try {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700410 cfg.getDevicesAddresses().forEach(addr -> {
helenyrwufd296b62016-06-22 17:43:02 -0700411 DeviceId deviceId = getDeviceId(addr.ip().toString(), addr.port());
412 Preconditions.checkNotNull(deviceId, ISNULL);
413 //Netconf configuration object
414 ChassisId cid = new ChassisId();
415 String ipAddress = addr.ip().toString();
416 SparseAnnotations annotations = DefaultAnnotations.builder()
417 .set(IPADDRESS, ipAddress)
418 .set(PORT, String.valueOf(addr.port()))
419 .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase())
420 .build();
421 DeviceDescription deviceDescription = new DefaultDeviceDescription(
422 deviceId.uri(),
423 Device.Type.SWITCH,
424 UNKNOWN, UNKNOWN,
425 UNKNOWN, UNKNOWN,
426 cid, false,
427 annotations);
Himanshu Ranjan7c2ee3c2017-02-13 05:10:08 -0600428 storeDeviceKey(addr, deviceId);
helenyrwufd296b62016-06-22 17:43:02 -0700429 checkAndUpdateDevice(deviceId, deviceDescription);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700430 });
andreaeb70a942015-10-16 21:34:46 -0700431 } catch (ConfigException e) {
432 log.error("Cannot read config error " + e);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530433 }
434 }
andreaeb70a942015-10-16 21:34:46 -0700435 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530436
Himanshu Ranjan7c2ee3c2017-02-13 05:10:08 -0600437 private void storeDeviceKey(NetconfProviderConfig.NetconfDeviceAddress addr, DeviceId deviceId) {
438 if (addr.sshkey().equals("")) {
439 deviceKeyAdminService.addKey(
440 DeviceKey.createDeviceKeyUsingUsernamePassword(
441 DeviceKeyId.deviceKeyId(deviceId.toString()),
442 null, addr.name(), addr.password()));
443 } else {
444 deviceKeyAdminService.addKey(
445 DeviceKey.createDeviceKeyUsingSshKey(
446 DeviceKeyId.deviceKeyId(deviceId.toString()),
447 null, addr.name(), addr.password(), addr.sshkey()));
448 }
449 }
450
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700451 private void initiateConnection(DeviceId deviceId, MastershipRole newRole) {
452 try {
453 if (isReachable(deviceId)) {
454 controller.connectDevice(deviceId);
455 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.MASTER);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700456 }
457 } catch (Exception e) {
458 if (deviceService.getDevice(deviceId) != null) {
459 providerService.deviceDisconnected(deviceId);
460 }
461 deviceKeyAdminService.removeKey(DeviceKeyId.deviceKeyId(deviceId.toString()));
462 throw new RuntimeException(new NetconfException(
463 "Can't connect to NETCONF " + "device on " + deviceId + ":" + deviceId, e));
464
465 }
466 }
467
468 private void discoverPorts(DeviceId deviceId) {
469 Device device = deviceService.getDevice(deviceId);
Andrea Campanella6c71a052016-04-22 11:56:31 -0700470 //TODO remove when PortDiscovery is removed from master
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700471 if (device.is(PortDiscovery.class)) {
472 PortDiscovery portConfig = device.as(PortDiscovery.class);
473 providerService.updatePorts(deviceId,
474 portConfig.getPorts());
Andrea Campanella6c71a052016-04-22 11:56:31 -0700475 } else if (device.is(DeviceDescriptionDiscovery.class)) {
476 DeviceDescriptionDiscovery deviceDescriptionDiscovery =
477 device.as(DeviceDescriptionDiscovery.class);
478 providerService.updatePorts(deviceId,
479 deviceDescriptionDiscovery.discoverPortDetails());
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700480 } else {
481 log.warn("No portGetter behaviour for device {}", deviceId);
482 }
Gaurav Agrawaldab4d772017-03-29 15:15:13 +0530483
484 // Port statistics discovery
485 if (device.is(PortStatisticsDiscovery.class)) {
486 PortStatisticsDiscovery d =
487 device.as(PortStatisticsDiscovery.class);
488 providerService.updatePortStatistics(deviceId,
489 d.discoverPortStatistics());
490 } else {
491 log.warn("No port statistics getter behaviour for device {}",
492 deviceId);
493 }
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700494 }
495
496 /**
497 * Return the DeviceId about the device containing the URI.
498 *
Andrea Campanella6c71a052016-04-22 11:56:31 -0700499 * @param ip IP address
Ray Milkeyd4334db2016-04-05 17:39:44 -0700500 * @param port port number
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700501 * @return DeviceId
502 */
503 public DeviceId getDeviceId(String ip, int port) {
504 try {
505 return DeviceId.deviceId(new URI(NETCONF, ip + ":" + port, null));
506 } catch (URISyntaxException e) {
507 throw new IllegalArgumentException("Unable to build deviceID for device "
508 + ip + ":" + port, e);
509 }
510 }
511
512 /**
513 * Listener for configuration events.
514 */
andreaeb70a942015-10-16 21:34:46 -0700515 private class InternalNetworkConfigListener implements NetworkConfigListener {
Sanjay Se8dcfee2015-04-23 10:07:08 +0530516
andreaeb70a942015-10-16 21:34:46 -0700517
518 @Override
519 public void event(NetworkConfigEvent event) {
Andrea Campanella90f044f2016-03-02 09:14:57 -0800520 executor.execute(NetconfDeviceProvider.this::connectDevices);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530521 }
522
andreaeb70a942015-10-16 21:34:46 -0700523 @Override
524 public boolean isRelevant(NetworkConfigEvent event) {
andreaeb70a942015-10-16 21:34:46 -0700525 return event.configClass().equals(NetconfProviderConfig.class) &&
526 (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
527 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530528 }
529 }
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700530
531 /**
532 * Listener for core device events.
533 */
534 private class InternalDeviceListener implements DeviceListener {
535 @Override
536 public void event(DeviceEvent event) {
537 if ((event.type() == DeviceEvent.Type.DEVICE_ADDED)) {
538 executor.execute(() -> discoverPorts(event.subject().id()));
539 } else if ((event.type() == DeviceEvent.Type.DEVICE_REMOVED)) {
540 log.debug("removing device {}", event.subject().id());
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700541 controller.disconnectDevice(event.subject().id(), true);
542 }
543 }
544
545 @Override
546 public boolean isRelevant(DeviceEvent event) {
547 if (mastershipService.getMasterFor(event.subject().id()) == null) {
548 return true;
549 }
Yuta HIGUCHI8c6a7e82017-03-14 18:35:43 -0700550 return SCHEME_NAME.toUpperCase()
551 .equals(event.subject().annotations().value(AnnotationKeys.PROTOCOL)) &&
Michele Santuari576f09c2016-09-28 14:20:00 +0200552 mastershipService.isLocalMaster(event.subject().id());
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700553 }
554 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530555}