blob: f8db0f4895380cb27c930b684612719f7d660a78 [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;
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -070024import org.apache.felix.scr.annotations.Modified;
25import org.apache.felix.scr.annotations.Property;
Sanjay Se8dcfee2015-04-23 10:07:08 +053026import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
28import org.onlab.packet.ChassisId;
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -070029import org.onlab.util.Tools;
30import org.onosproject.cfg.ComponentConfigService;
andreaeb70a942015-10-16 21:34:46 -070031import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
33import org.onosproject.incubator.net.config.basics.ConfigException;
Andrea Campanella7e6200a2016-03-21 09:48:40 -070034import org.onosproject.mastership.MastershipService;
Marc De Leenheerb0d131c2016-03-01 20:34:59 -080035import org.onosproject.net.AnnotationKeys;
andreaeb70a942015-10-16 21:34:46 -070036import org.onosproject.net.DefaultAnnotations;
Sanjay Se8dcfee2015-04-23 10:07:08 +053037import org.onosproject.net.Device;
38import org.onosproject.net.DeviceId;
39import org.onosproject.net.MastershipRole;
Saurav Dasa2d37502016-03-25 17:50:40 -070040import org.onosproject.net.PortNumber;
andreaeb70a942015-10-16 21:34:46 -070041import org.onosproject.net.SparseAnnotations;
Aaron Kruglikov17b4c852016-01-15 16:37:04 -080042import org.onosproject.net.behaviour.PortDiscovery;
andreaeb70a942015-10-16 21:34:46 -070043import org.onosproject.net.config.ConfigFactory;
44import org.onosproject.net.config.NetworkConfigEvent;
45import org.onosproject.net.config.NetworkConfigListener;
46import org.onosproject.net.config.NetworkConfigRegistry;
Sanjay Se8dcfee2015-04-23 10:07:08 +053047import org.onosproject.net.device.DefaultDeviceDescription;
48import org.onosproject.net.device.DeviceDescription;
Andrea Campanella6c71a052016-04-22 11:56:31 -070049import org.onosproject.net.device.DeviceDescriptionDiscovery;
Andrea Campanella7e6200a2016-03-21 09:48:40 -070050import org.onosproject.net.device.DeviceEvent;
51import org.onosproject.net.device.DeviceListener;
Sanjay Se8dcfee2015-04-23 10:07:08 +053052import org.onosproject.net.device.DeviceProvider;
53import org.onosproject.net.device.DeviceProviderRegistry;
54import org.onosproject.net.device.DeviceProviderService;
Aaron Kruglikov17b4c852016-01-15 16:37:04 -080055import org.onosproject.net.device.DeviceService;
Gaurav Agrawaldab4d772017-03-29 15:15:13 +053056import org.onosproject.net.device.PortStatisticsDiscovery;
Andrea Campanella7e6200a2016-03-21 09:48:40 -070057import org.onosproject.net.key.DeviceKey;
58import org.onosproject.net.key.DeviceKeyAdminService;
59import org.onosproject.net.key.DeviceKeyId;
Sanjay Se8dcfee2015-04-23 10:07:08 +053060import org.onosproject.net.provider.AbstractProvider;
61import org.onosproject.net.provider.ProviderId;
andreaeb70a942015-10-16 21:34:46 -070062import org.onosproject.netconf.NetconfController;
andreaeb70a942015-10-16 21:34:46 -070063import org.onosproject.netconf.NetconfDeviceListener;
Andrea Campanella8b1cb672016-01-25 13:58:58 -080064import org.onosproject.netconf.NetconfException;
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -070065import org.osgi.service.component.ComponentContext;
Sanjay Se8dcfee2015-04-23 10:07:08 +053066import org.slf4j.Logger;
67
Andrea Campanella087ceb92015-12-07 09:58:34 -080068import java.io.IOException;
Andrea Campanella7e6200a2016-03-21 09:48:40 -070069import java.net.Socket;
70import java.net.URI;
71import java.net.URISyntaxException;
72import java.util.Arrays;
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -070073import java.util.Dictionary;
Andrea Campanella5c999e22016-03-01 15:12:53 -080074import java.util.concurrent.ExecutorService;
75import java.util.concurrent.Executors;
helenyrwufd296b62016-06-22 17:43:02 -070076import java.util.concurrent.ScheduledExecutorService;
77import java.util.concurrent.ScheduledFuture;
78import java.util.concurrent.TimeUnit;
andreaeb70a942015-10-16 21:34:46 -070079
Yuta HIGUCHI1624df12016-07-21 16:54:33 -070080import static java.util.concurrent.Executors.newScheduledThreadPool;
Andrea Campanella5c999e22016-03-01 15:12:53 -080081import static org.onlab.util.Tools.groupedThreads;
andreaeb70a942015-10-16 21:34:46 -070082import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
83import static org.slf4j.LoggerFactory.getLogger;
84
Sanjay Se8dcfee2015-04-23 10:07:08 +053085/**
andreaeb70a942015-10-16 21:34:46 -070086 * Provider which uses an NETCONF controller to detect device.
Sanjay Se8dcfee2015-04-23 10:07:08 +053087 */
88@Component(immediate = true)
89public class NetconfDeviceProvider extends AbstractProvider
90 implements DeviceProvider {
Andrea Campanella7e6200a2016-03-21 09:48:40 -070091
andreaeb70a942015-10-16 21:34:46 -070092 private final Logger log = getLogger(getClass());
Sanjay Se8dcfee2015-04-23 10:07:08 +053093
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected DeviceProviderRegistry providerRegistry;
96
andreaeb70a942015-10-16 21:34:46 -070097 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanella101417d2015-12-11 17:58:07 -080098 protected NetconfController controller;
Sanjay Se8dcfee2015-04-23 10:07:08 +053099
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
andreaeb70a942015-10-16 21:34:46 -0700101 protected NetworkConfigRegistry cfgService;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530102
Thomas Vachuskad6811712015-04-29 21:37:04 -0700103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
andreaeb70a942015-10-16 21:34:46 -0700104 protected CoreService coreService;
Thomas Vachuskad6811712015-04-29 21:37:04 -0700105
Aaron Kruglikov17b4c852016-01-15 16:37:04 -0800106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700107 protected DeviceService deviceService;
Aaron Kruglikov17b4c852016-01-15 16:37:04 -0800108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700110 protected DeviceKeyAdminService deviceKeyAdminService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected MastershipService mastershipService;
114
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected ComponentConfigService componentConfigService;
117
118
119
Michele Santuari576f09c2016-09-28 14:20:00 +0200120 protected static final String APP_NAME = "org.onosproject.netconf";
Andrea Campanella101417d2015-12-11 17:58:07 -0800121 private static final String SCHEME_NAME = "netconf";
122 private static final String DEVICE_PROVIDER_PACKAGE = "org.onosproject.netconf.provider.device";
123 private static final String UNKNOWN = "unknown";
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700124 protected static final String ISNULL = "NetconfDeviceInfo is null";
125 private static final String IPADDRESS = "ipaddress";
126 private static final String NETCONF = "netconf";
127 private static final String PORT = "port";
helenyrwufd296b62016-06-22 17:43:02 -0700128 private static final int CORE_POOL_SIZE = 10;
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700129
130 private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 10;
131 @Property(name = "pollFrequency", intValue = DEFAULT_POLL_FREQUENCY_SECONDS,
132 label = "Configure poll frequency for port status and statistics; " +
133 "default is 10 sec")
134 private int pollFrequency = DEFAULT_POLL_FREQUENCY_SECONDS;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530135
Michele Santuari576f09c2016-09-28 14:20:00 +0200136 protected final ExecutorService executor =
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700137 Executors.newFixedThreadPool(5, groupedThreads("onos/netconfdeviceprovider",
138 "device-installer-%d", log));
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700139 protected ScheduledExecutorService connectionExecutor
140 = newScheduledThreadPool(CORE_POOL_SIZE,
141 groupedThreads("onos/netconfdeviceprovider",
142 "connection-executor-%d", log));
Andrea Campanella5c999e22016-03-01 15:12:53 -0800143
Michele Santuari576f09c2016-09-28 14:20:00 +0200144 protected DeviceProviderService providerService;
andreaeb70a942015-10-16 21:34:46 -0700145 private NetconfDeviceListener innerNodeListener = new InnerNetconfDeviceListener();
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700146 private InternalDeviceListener deviceListener = new InternalDeviceListener();
Michele Santuari576f09c2016-09-28 14:20:00 +0200147 protected ScheduledFuture<?> scheduledTask;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530148
andreaeb70a942015-10-16 21:34:46 -0700149 private final ConfigFactory factory =
150 new ConfigFactory<ApplicationId, NetconfProviderConfig>(APP_SUBJECT_FACTORY,
151 NetconfProviderConfig.class,
152 "devices",
153 true) {
154 @Override
155 public NetconfProviderConfig createConfig() {
156 return new NetconfProviderConfig();
157 }
158 };
Michele Santuari576f09c2016-09-28 14:20:00 +0200159 protected final NetworkConfigListener cfgListener = new InternalNetworkConfigListener();
andreaeb70a942015-10-16 21:34:46 -0700160 private ApplicationId appId;
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700161 private boolean active;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530162
Sanjay Se8dcfee2015-04-23 10:07:08 +0530163
164 @Activate
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700165 public void activate(ComponentContext context) {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700166 active = true;
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700167 componentConfigService.registerProperties(getClass());
Sanjay Se8dcfee2015-04-23 10:07:08 +0530168 providerService = providerRegistry.register(this);
Andrea Campanella101417d2015-12-11 17:58:07 -0800169 appId = coreService.registerApplication(APP_NAME);
andreaeb70a942015-10-16 21:34:46 -0700170 cfgService.registerConfigFactory(factory);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700171 cfgService.addListener(cfgListener);
andreaeb70a942015-10-16 21:34:46 -0700172 controller.addDeviceListener(innerNodeListener);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700173 deviceService.addListener(deviceListener);
Andrea Campanella7d8449b2016-03-02 10:16:42 -0800174 executor.execute(NetconfDeviceProvider.this::connectDevices);
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700175 modified(context);
Thomas Vachuskad6811712015-04-29 21:37:04 -0700176 log.info("Started");
Sanjay Se8dcfee2015-04-23 10:07:08 +0530177 }
178
andreaeb70a942015-10-16 21:34:46 -0700179
Sanjay Se8dcfee2015-04-23 10:07:08 +0530180 @Deactivate
andreaeb70a942015-10-16 21:34:46 -0700181 public void deactivate() {
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700182 componentConfigService.unregisterProperties(getClass(), false);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700183 deviceService.removeListener(deviceListener);
184 active = false;
185 controller.getNetconfDevices().forEach(id -> {
186 deviceKeyAdminService.removeKey(DeviceKeyId.deviceKeyId(id.toString()));
187 controller.disconnectDevice(id, true);
188 });
Andrea Campanella86294db2016-03-07 11:42:49 -0800189 controller.removeDeviceListener(innerNodeListener);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700190 deviceService.removeListener(deviceListener);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530191 providerRegistry.unregister(this);
192 providerService = null;
andreaeb70a942015-10-16 21:34:46 -0700193 cfgService.unregisterConfigFactory(factory);
helenyrwufd296b62016-06-22 17:43:02 -0700194 scheduledTask.cancel(true);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700195 executor.shutdown();
Sanjay Seb5eebb2015-04-24 15:44:50 +0530196 log.info("Stopped");
Sanjay Se8dcfee2015-04-23 10:07:08 +0530197 }
198
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700199
200 @Modified
201 public void modified(ComponentContext context) {
202 if (context != null) {
203 Dictionary<?, ?> properties = context.getProperties();
204 pollFrequency = Tools.getIntegerProperty(properties, "pollFrequency",
205 DEFAULT_POLL_FREQUENCY_SECONDS);
206 log.info("Configured. Poll frequency is configured to {} seconds", pollFrequency);
207 }
208 if (scheduledTask != null) {
209 scheduledTask.cancel(false);
210 }
211 scheduledTask = schedulePolling();
212 }
213
andreaeb70a942015-10-16 21:34:46 -0700214 public NetconfDeviceProvider() {
Andrea Campanella101417d2015-12-11 17:58:07 -0800215 super(new ProviderId(SCHEME_NAME, DEVICE_PROVIDER_PACKAGE));
Sanjay Se8dcfee2015-04-23 10:07:08 +0530216 }
217
helenyrwufd296b62016-06-22 17:43:02 -0700218 // Checks connection to devices in the config file
219 // every DEFAULT_POLL_FREQUENCY_SECONDS seconds.
220 private ScheduledFuture schedulePolling() {
Yuta HIGUCHIc2b82e32017-03-10 14:33:41 -0800221 return connectionExecutor.scheduleAtFixedRate(exceptionSafe(this::checkAndUpdateDevices),
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700222 pollFrequency / 10,
223 pollFrequency, TimeUnit.SECONDS);
helenyrwufd296b62016-06-22 17:43:02 -0700224 }
225
Yuta HIGUCHIc2b82e32017-03-10 14:33:41 -0800226 private Runnable exceptionSafe(Runnable runnable) {
227 return new Runnable() {
228
229 @Override
230 public void run() {
231 try {
232 runnable.run();
233 } catch (Exception e) {
234 log.error("Unhandled Exception", e);
235 }
236 }
237 };
238 }
239
Sanjay Se8dcfee2015-04-23 10:07:08 +0530240 @Override
241 public void triggerProbe(DeviceId deviceId) {
andreaeb70a942015-10-16 21:34:46 -0700242 // TODO: This will be implemented later.
243 log.info("Triggering probe on device {}", deviceId);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530244 }
245
246 @Override
247 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700248 if (active) {
249 switch (newRole) {
250 case MASTER:
251 initiateConnection(deviceId, newRole);
252 log.debug("Accepting mastership role change to {} for device {}", newRole, deviceId);
253 break;
254 case STANDBY:
255 controller.disconnectDevice(deviceId, false);
256 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.STANDBY);
257 //else no-op
258 break;
259 case NONE:
260 controller.disconnectDevice(deviceId, false);
261 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.NONE);
262 break;
263 default:
264 log.error("Unimplemented Mastership state : {}", newRole);
265
266 }
267 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530268 }
269
270 @Override
271 public boolean isReachable(DeviceId deviceId) {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700272 //FIXME this is a workaround util device state is shared
273 // between controller instances.
274 Device device = deviceService.getDevice(deviceId);
275 String ip;
276 int port;
277 Socket socket = null;
278 if (device != null) {
279 ip = device.annotations().value(IPADDRESS);
280 port = Integer.parseInt(device.annotations().value(PORT));
281 } else {
282 String[] info = deviceId.toString().split(":");
283 if (info.length == 3) {
284 ip = info[1];
285 port = Integer.parseInt(info[2]);
286 } else {
287 ip = Arrays.asList(info).stream().filter(el -> !el.equals(info[0])
288 && !el.equals(info[info.length - 1]))
289 .reduce((t, u) -> t + ":" + u)
290 .get();
291 log.debug("ip v6 {}", ip);
292 port = Integer.parseInt(info[info.length - 1]);
293 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530294 }
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700295 //test connection to device opening a socket to it.
296 try {
297 socket = new Socket(ip, port);
Yuta HIGUCHI0454d702017-03-17 10:08:38 -0700298 log.debug("rechability of {}, {}, {}", deviceId, socket.isConnected(), !socket.isClosed());
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700299 return socket.isConnected() && !socket.isClosed();
300 } catch (IOException e) {
301 log.info("Device {} is not reachable", deviceId);
302 return false;
303 } finally {
304 if (socket != null) {
305 try {
306 socket.close();
307 } catch (IOException e) {
308 log.debug("Test Socket failed {} ", deviceId);
309 return false;
310 }
311 }
312 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530313 }
314
Saurav Dasa2d37502016-03-25 17:50:40 -0700315 @Override
316 public void changePortState(DeviceId deviceId, PortNumber portNumber,
317 boolean enable) {
318 // TODO if required
319 }
320
andreaeb70a942015-10-16 21:34:46 -0700321 private class InnerNetconfDeviceListener implements NetconfDeviceListener {
Sanjay Se8dcfee2015-04-23 10:07:08 +0530322
Andrea Campanella101417d2015-12-11 17:58:07 -0800323
andreaeb70a942015-10-16 21:34:46 -0700324 @Override
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700325 public void deviceAdded(DeviceId deviceId) {
326 //no-op
327 log.debug("Netconf device {} added to Netconf subController", deviceId);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530328 }
329
330 @Override
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700331 public void deviceRemoved(DeviceId deviceId) {
332 Preconditions.checkNotNull(deviceId, ISNULL);
helenyrwufd296b62016-06-22 17:43:02 -0700333
334 if (deviceService.getDevice(deviceId) != null) {
335 providerService.deviceDisconnected(deviceId);
336 log.debug("Netconf device {} removed from Netconf subController", deviceId);
337 } else {
338 log.warn("Netconf device {} does not exist in the store, " +
Vidyashree Ramad89a1532017-03-30 15:13:52 +0530339 "it may already have been removed", deviceId);
helenyrwufd296b62016-06-22 17:43:02 -0700340 }
andreaeb70a942015-10-16 21:34:46 -0700341 }
342 }
343
andreaeb70a942015-10-16 21:34:46 -0700344 private void connectDevices() {
345 NetconfProviderConfig cfg = cfgService.getConfig(appId, NetconfProviderConfig.class);
346 if (cfg != null) {
Sanjay Se8dcfee2015-04-23 10:07:08 +0530347 try {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700348 cfg.getDevicesAddresses().forEach(addr -> {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700349 DeviceId deviceId = getDeviceId(addr.ip().toString(), addr.port());
350 Preconditions.checkNotNull(deviceId, ISNULL);
351 //Netconf configuration object
352 ChassisId cid = new ChassisId();
353 String ipAddress = addr.ip().toString();
354 SparseAnnotations annotations = DefaultAnnotations.builder()
355 .set(IPADDRESS, ipAddress)
356 .set(PORT, String.valueOf(addr.port()))
357 .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase())
358 .build();
359 DeviceDescription deviceDescription = new DefaultDeviceDescription(
360 deviceId.uri(),
361 Device.Type.SWITCH,
362 UNKNOWN, UNKNOWN,
363 UNKNOWN, UNKNOWN,
helenyrwufd296b62016-06-22 17:43:02 -0700364 cid, false,
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700365 annotations);
Himanshu Ranjan7c2ee3c2017-02-13 05:10:08 -0600366 storeDeviceKey(addr, deviceId);
367
helenyrwufd296b62016-06-22 17:43:02 -0700368 if (deviceService.getDevice(deviceId) == null) {
369 providerService.deviceConnected(deviceId, deviceDescription);
370 }
Yuta HIGUCHIc2b82e32017-03-10 14:33:41 -0800371 try {
372 checkAndUpdateDevice(deviceId, deviceDescription);
373 } catch (Exception e) {
374 log.error("Unhandled exception checking {}", deviceId, e);
375 }
helenyrwufd296b62016-06-22 17:43:02 -0700376 });
377 } catch (ConfigException e) {
378 log.error("Cannot read config error " + e);
379 }
380 }
381 }
382
383 private void checkAndUpdateDevice(DeviceId deviceId, DeviceDescription deviceDescription) {
Vidyashree Ramad89a1532017-03-30 15:13:52 +0530384 Device device = deviceService.getDevice(deviceId);
385 if (device == null) {
helenyrwufd296b62016-06-22 17:43:02 -0700386 log.warn("Device {} has not been added to store, " +
387 "maybe due to a problem in connectivity", deviceId);
388 } else {
389 boolean isReachable = isReachable(deviceId);
390 if (isReachable && !deviceService.isAvailable(deviceId)) {
Konstantinos Kanonakis4d67dd82016-08-05 12:18:52 -0500391 if (device.is(DeviceDescriptionDiscovery.class)) {
392 if (mastershipService.isLocalMaster(deviceId)) {
393 DeviceDescriptionDiscovery deviceDescriptionDiscovery =
394 device.as(DeviceDescriptionDiscovery.class);
Michele Santuari00cc1f72016-09-08 17:05:24 +0200395 DeviceDescription updatedDeviceDescription = deviceDescriptionDiscovery.discoverDeviceDetails();
396 if (updatedDeviceDescription != null &&
397 !descriptionEquals(device, updatedDeviceDescription)) {
398 providerService.deviceConnected(
399 deviceId, new DefaultDeviceDescription(
400 updatedDeviceDescription, true, updatedDeviceDescription.annotations()));
Michele Santuari576f09c2016-09-28 14:20:00 +0200401 } else if (updatedDeviceDescription == null) {
402 providerService.deviceConnected(
403 deviceId, new DefaultDeviceDescription(
404 deviceDescription, true, deviceDescription.annotations()));
Michele Santuari00cc1f72016-09-08 17:05:24 +0200405 }
406 //if ports are not discovered, retry the discovery
407 if (deviceService.getPorts(deviceId).isEmpty()) {
408 discoverPorts(deviceId);
409 }
Konstantinos Kanonakis4d67dd82016-08-05 12:18:52 -0500410 }
411 } else {
Michele Santuari576f09c2016-09-28 14:20:00 +0200412 log.warn("No DeviceDescriptionDiscovery behaviour for device {} " +
413 "using DefaultDeviceDescription", deviceId);
Vidyashree Ramad89a1532017-03-30 15:13:52 +0530414 providerService.deviceConnected(
415 deviceId, new DefaultDeviceDescription(
Michele Santuari576f09c2016-09-28 14:20:00 +0200416 deviceDescription, true, deviceDescription.annotations()));
Konstantinos Kanonakis4d67dd82016-08-05 12:18:52 -0500417 }
helenyrwufd296b62016-06-22 17:43:02 -0700418 } else if (!isReachable && deviceService.isAvailable(deviceId)) {
419 providerService.deviceDisconnected(deviceId);
Vidyashree Ramad89a1532017-03-30 15:13:52 +0530420 } else if (isReachable && deviceService.isAvailable(deviceId)) {
421 updatePortStatistics(device);
helenyrwufd296b62016-06-22 17:43:02 -0700422 }
423 }
424 }
425
Vidyashree Ramad89a1532017-03-30 15:13:52 +0530426 private void updatePortStatistics(Device device) {
427 if (device.is(PortStatisticsDiscovery.class)) {
428 PortStatisticsDiscovery d = device.as(PortStatisticsDiscovery.class);
429 providerService.updatePortStatistics(device.id(),
430 d.discoverPortStatistics());
431 } else {
432 log.warn("No port statistics getter behaviour for device {}",
433 device.id());
434 }
435 }
436
Michele Santuari00cc1f72016-09-08 17:05:24 +0200437 private boolean descriptionEquals(Device device, DeviceDescription updatedDeviceDescription) {
Yuta HIGUCHIf381fc72017-01-03 10:39:36 -0800438 return Objects.equal(device.id().uri(), updatedDeviceDescription.deviceUri())
Michele Santuari00cc1f72016-09-08 17:05:24 +0200439 && Objects.equal(device.type(), updatedDeviceDescription.type())
440 && Objects.equal(device.manufacturer(), updatedDeviceDescription.manufacturer())
441 && Objects.equal(device.hwVersion(), updatedDeviceDescription.hwVersion())
442 && Objects.equal(device.swVersion(), updatedDeviceDescription.swVersion())
443 && Objects.equal(device.serialNumber(), updatedDeviceDescription.serialNumber())
444 && Objects.equal(device.chassisId(), updatedDeviceDescription.chassisId())
445 && Objects.equal(device.annotations(), updatedDeviceDescription.annotations());
446 }
447
helenyrwufd296b62016-06-22 17:43:02 -0700448 private void checkAndUpdateDevices() {
449 NetconfProviderConfig cfg = cfgService.getConfig(appId, NetconfProviderConfig.class);
450 if (cfg != null) {
451 log.info("Checking connection to devices in configuration");
452 try {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700453 cfg.getDevicesAddresses().forEach(addr -> {
helenyrwufd296b62016-06-22 17:43:02 -0700454 DeviceId deviceId = getDeviceId(addr.ip().toString(), addr.port());
455 Preconditions.checkNotNull(deviceId, ISNULL);
456 //Netconf configuration object
457 ChassisId cid = new ChassisId();
458 String ipAddress = addr.ip().toString();
459 SparseAnnotations annotations = DefaultAnnotations.builder()
460 .set(IPADDRESS, ipAddress)
461 .set(PORT, String.valueOf(addr.port()))
462 .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase())
463 .build();
464 DeviceDescription deviceDescription = new DefaultDeviceDescription(
465 deviceId.uri(),
466 Device.Type.SWITCH,
467 UNKNOWN, UNKNOWN,
468 UNKNOWN, UNKNOWN,
469 cid, false,
470 annotations);
Himanshu Ranjan7c2ee3c2017-02-13 05:10:08 -0600471 storeDeviceKey(addr, deviceId);
helenyrwufd296b62016-06-22 17:43:02 -0700472 checkAndUpdateDevice(deviceId, deviceDescription);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700473 });
andreaeb70a942015-10-16 21:34:46 -0700474 } catch (ConfigException e) {
475 log.error("Cannot read config error " + e);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530476 }
477 }
andreaeb70a942015-10-16 21:34:46 -0700478 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530479
Himanshu Ranjan7c2ee3c2017-02-13 05:10:08 -0600480 private void storeDeviceKey(NetconfProviderConfig.NetconfDeviceAddress addr, DeviceId deviceId) {
481 if (addr.sshkey().equals("")) {
482 deviceKeyAdminService.addKey(
483 DeviceKey.createDeviceKeyUsingUsernamePassword(
484 DeviceKeyId.deviceKeyId(deviceId.toString()),
485 null, addr.name(), addr.password()));
486 } else {
487 deviceKeyAdminService.addKey(
488 DeviceKey.createDeviceKeyUsingSshKey(
489 DeviceKeyId.deviceKeyId(deviceId.toString()),
490 null, addr.name(), addr.password(), addr.sshkey()));
491 }
492 }
493
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700494 private void initiateConnection(DeviceId deviceId, MastershipRole newRole) {
495 try {
496 if (isReachable(deviceId)) {
497 controller.connectDevice(deviceId);
498 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.MASTER);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700499 }
500 } catch (Exception e) {
501 if (deviceService.getDevice(deviceId) != null) {
502 providerService.deviceDisconnected(deviceId);
503 }
504 deviceKeyAdminService.removeKey(DeviceKeyId.deviceKeyId(deviceId.toString()));
505 throw new RuntimeException(new NetconfException(
506 "Can't connect to NETCONF " + "device on " + deviceId + ":" + deviceId, e));
507
508 }
509 }
510
511 private void discoverPorts(DeviceId deviceId) {
512 Device device = deviceService.getDevice(deviceId);
Andrea Campanella6c71a052016-04-22 11:56:31 -0700513 //TODO remove when PortDiscovery is removed from master
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700514 if (device.is(PortDiscovery.class)) {
515 PortDiscovery portConfig = device.as(PortDiscovery.class);
516 providerService.updatePorts(deviceId,
517 portConfig.getPorts());
Andrea Campanella6c71a052016-04-22 11:56:31 -0700518 } else if (device.is(DeviceDescriptionDiscovery.class)) {
519 DeviceDescriptionDiscovery deviceDescriptionDiscovery =
520 device.as(DeviceDescriptionDiscovery.class);
521 providerService.updatePorts(deviceId,
522 deviceDescriptionDiscovery.discoverPortDetails());
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700523 } else {
524 log.warn("No portGetter behaviour for device {}", deviceId);
525 }
Gaurav Agrawaldab4d772017-03-29 15:15:13 +0530526
527 // Port statistics discovery
Vidyashree Ramad89a1532017-03-30 15:13:52 +0530528 updatePortStatistics(device);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700529 }
530
531 /**
532 * Return the DeviceId about the device containing the URI.
533 *
Andrea Campanella6c71a052016-04-22 11:56:31 -0700534 * @param ip IP address
Ray Milkeyd4334db2016-04-05 17:39:44 -0700535 * @param port port number
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700536 * @return DeviceId
537 */
538 public DeviceId getDeviceId(String ip, int port) {
539 try {
540 return DeviceId.deviceId(new URI(NETCONF, ip + ":" + port, null));
541 } catch (URISyntaxException e) {
542 throw new IllegalArgumentException("Unable to build deviceID for device "
543 + ip + ":" + port, e);
544 }
545 }
546
547 /**
548 * Listener for configuration events.
549 */
andreaeb70a942015-10-16 21:34:46 -0700550 private class InternalNetworkConfigListener implements NetworkConfigListener {
Sanjay Se8dcfee2015-04-23 10:07:08 +0530551
andreaeb70a942015-10-16 21:34:46 -0700552
553 @Override
554 public void event(NetworkConfigEvent event) {
Andrea Campanella90f044f2016-03-02 09:14:57 -0800555 executor.execute(NetconfDeviceProvider.this::connectDevices);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530556 }
557
andreaeb70a942015-10-16 21:34:46 -0700558 @Override
559 public boolean isRelevant(NetworkConfigEvent event) {
andreaeb70a942015-10-16 21:34:46 -0700560 return event.configClass().equals(NetconfProviderConfig.class) &&
561 (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
562 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530563 }
564 }
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700565
566 /**
567 * Listener for core device events.
568 */
569 private class InternalDeviceListener implements DeviceListener {
570 @Override
571 public void event(DeviceEvent event) {
572 if ((event.type() == DeviceEvent.Type.DEVICE_ADDED)) {
573 executor.execute(() -> discoverPorts(event.subject().id()));
574 } else if ((event.type() == DeviceEvent.Type.DEVICE_REMOVED)) {
575 log.debug("removing device {}", event.subject().id());
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700576 controller.disconnectDevice(event.subject().id(), true);
577 }
578 }
579
580 @Override
581 public boolean isRelevant(DeviceEvent event) {
582 if (mastershipService.getMasterFor(event.subject().id()) == null) {
583 return true;
584 }
Yuta HIGUCHI8c6a7e82017-03-14 18:35:43 -0700585 return SCHEME_NAME.toUpperCase()
586 .equals(event.subject().annotations().value(AnnotationKeys.PROTOCOL)) &&
Michele Santuari576f09c2016-09-28 14:20:00 +0200587 mastershipService.isLocalMaster(event.subject().id());
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700588 }
589 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530590}