blob: 215f104576ffc6936266e223ffeaf3efd7fadb18 [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;
Andrea Campanellac3627842017-04-04 18:06:54 +020056import org.onosproject.net.device.PortStatistics;
Gaurav Agrawaldab4d772017-03-29 15:15:13 +053057import org.onosproject.net.device.PortStatisticsDiscovery;
Andrea Campanella7e6200a2016-03-21 09:48:40 -070058import org.onosproject.net.key.DeviceKey;
59import org.onosproject.net.key.DeviceKeyAdminService;
60import org.onosproject.net.key.DeviceKeyId;
Sanjay Se8dcfee2015-04-23 10:07:08 +053061import org.onosproject.net.provider.AbstractProvider;
62import org.onosproject.net.provider.ProviderId;
andreaeb70a942015-10-16 21:34:46 -070063import org.onosproject.netconf.NetconfController;
andreaeb70a942015-10-16 21:34:46 -070064import org.onosproject.netconf.NetconfDeviceListener;
Andrea Campanella8b1cb672016-01-25 13:58:58 -080065import org.onosproject.netconf.NetconfException;
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -070066import org.osgi.service.component.ComponentContext;
Sanjay Se8dcfee2015-04-23 10:07:08 +053067import org.slf4j.Logger;
68
Andrea Campanella087ceb92015-12-07 09:58:34 -080069import java.io.IOException;
Andrea Campanella7e6200a2016-03-21 09:48:40 -070070import java.net.Socket;
71import java.net.URI;
72import java.net.URISyntaxException;
73import java.util.Arrays;
Andrea Campanellac3627842017-04-04 18:06:54 +020074import java.util.Collection;
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -070075import java.util.Dictionary;
Andrea Campanella5c999e22016-03-01 15:12:53 -080076import java.util.concurrent.ExecutorService;
77import java.util.concurrent.Executors;
helenyrwufd296b62016-06-22 17:43:02 -070078import java.util.concurrent.ScheduledExecutorService;
79import java.util.concurrent.ScheduledFuture;
80import java.util.concurrent.TimeUnit;
andreaeb70a942015-10-16 21:34:46 -070081
Yuta HIGUCHI1624df12016-07-21 16:54:33 -070082import static java.util.concurrent.Executors.newScheduledThreadPool;
Andrea Campanella5c999e22016-03-01 15:12:53 -080083import static org.onlab.util.Tools.groupedThreads;
andreaeb70a942015-10-16 21:34:46 -070084import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
85import static org.slf4j.LoggerFactory.getLogger;
86
Sanjay Se8dcfee2015-04-23 10:07:08 +053087/**
andreaeb70a942015-10-16 21:34:46 -070088 * Provider which uses an NETCONF controller to detect device.
Sanjay Se8dcfee2015-04-23 10:07:08 +053089 */
90@Component(immediate = true)
91public class NetconfDeviceProvider extends AbstractProvider
92 implements DeviceProvider {
Andrea Campanella7e6200a2016-03-21 09:48:40 -070093
andreaeb70a942015-10-16 21:34:46 -070094 private final Logger log = getLogger(getClass());
Sanjay Se8dcfee2015-04-23 10:07:08 +053095
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected DeviceProviderRegistry providerRegistry;
98
andreaeb70a942015-10-16 21:34:46 -070099 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanella101417d2015-12-11 17:58:07 -0800100 protected NetconfController controller;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
andreaeb70a942015-10-16 21:34:46 -0700103 protected NetworkConfigRegistry cfgService;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530104
Thomas Vachuskad6811712015-04-29 21:37:04 -0700105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
andreaeb70a942015-10-16 21:34:46 -0700106 protected CoreService coreService;
Thomas Vachuskad6811712015-04-29 21:37:04 -0700107
Aaron Kruglikov17b4c852016-01-15 16:37:04 -0800108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700109 protected DeviceService deviceService;
Aaron Kruglikov17b4c852016-01-15 16:37:04 -0800110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700112 protected DeviceKeyAdminService deviceKeyAdminService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected MastershipService mastershipService;
116
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected ComponentConfigService componentConfigService;
119
120
Michele Santuari576f09c2016-09-28 14:20:00 +0200121 protected static final String APP_NAME = "org.onosproject.netconf";
Andrea Campanella101417d2015-12-11 17:58:07 -0800122 private static final String SCHEME_NAME = "netconf";
123 private static final String DEVICE_PROVIDER_PACKAGE = "org.onosproject.netconf.provider.device";
124 private static final String UNKNOWN = "unknown";
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700125 protected static final String ISNULL = "NetconfDeviceInfo is null";
126 private static final String IPADDRESS = "ipaddress";
127 private static final String NETCONF = "netconf";
128 private static final String PORT = "port";
helenyrwufd296b62016-06-22 17:43:02 -0700129 private static final int CORE_POOL_SIZE = 10;
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700130
Thomas Vachuskadb29dcf2017-03-31 11:26:19 -0700131 private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 30;
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700132 @Property(name = "pollFrequency", intValue = DEFAULT_POLL_FREQUENCY_SECONDS,
133 label = "Configure poll frequency for port status and statistics; " +
Thomas Vachuskadb29dcf2017-03-31 11:26:19 -0700134 "default is 30 sec")
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700135 private int pollFrequency = DEFAULT_POLL_FREQUENCY_SECONDS;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530136
Michele Santuari576f09c2016-09-28 14:20:00 +0200137 protected final ExecutorService executor =
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700138 Executors.newFixedThreadPool(5, groupedThreads("onos/netconfdeviceprovider",
139 "device-installer-%d", log));
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700140 protected ScheduledExecutorService connectionExecutor
141 = newScheduledThreadPool(CORE_POOL_SIZE,
142 groupedThreads("onos/netconfdeviceprovider",
143 "connection-executor-%d", log));
Andrea Campanella5c999e22016-03-01 15:12:53 -0800144
Michele Santuari576f09c2016-09-28 14:20:00 +0200145 protected DeviceProviderService providerService;
andreaeb70a942015-10-16 21:34:46 -0700146 private NetconfDeviceListener innerNodeListener = new InnerNetconfDeviceListener();
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700147 private InternalDeviceListener deviceListener = new InternalDeviceListener();
Michele Santuari576f09c2016-09-28 14:20:00 +0200148 protected ScheduledFuture<?> scheduledTask;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530149
andreaeb70a942015-10-16 21:34:46 -0700150 private final ConfigFactory factory =
151 new ConfigFactory<ApplicationId, NetconfProviderConfig>(APP_SUBJECT_FACTORY,
152 NetconfProviderConfig.class,
153 "devices",
154 true) {
155 @Override
156 public NetconfProviderConfig createConfig() {
157 return new NetconfProviderConfig();
158 }
159 };
Michele Santuari576f09c2016-09-28 14:20:00 +0200160 protected final NetworkConfigListener cfgListener = new InternalNetworkConfigListener();
andreaeb70a942015-10-16 21:34:46 -0700161 private ApplicationId appId;
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700162 private boolean active;
Sanjay Se8dcfee2015-04-23 10:07:08 +0530163
Sanjay Se8dcfee2015-04-23 10:07:08 +0530164
165 @Activate
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700166 public void activate(ComponentContext context) {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700167 active = true;
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700168 componentConfigService.registerProperties(getClass());
Sanjay Se8dcfee2015-04-23 10:07:08 +0530169 providerService = providerRegistry.register(this);
Andrea Campanella101417d2015-12-11 17:58:07 -0800170 appId = coreService.registerApplication(APP_NAME);
andreaeb70a942015-10-16 21:34:46 -0700171 cfgService.registerConfigFactory(factory);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700172 cfgService.addListener(cfgListener);
andreaeb70a942015-10-16 21:34:46 -0700173 controller.addDeviceListener(innerNodeListener);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700174 deviceService.addListener(deviceListener);
Andrea Campanella7d8449b2016-03-02 10:16:42 -0800175 executor.execute(NetconfDeviceProvider.this::connectDevices);
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700176 modified(context);
Thomas Vachuskad6811712015-04-29 21:37:04 -0700177 log.info("Started");
Sanjay Se8dcfee2015-04-23 10:07:08 +0530178 }
179
andreaeb70a942015-10-16 21:34:46 -0700180
Sanjay Se8dcfee2015-04-23 10:07:08 +0530181 @Deactivate
andreaeb70a942015-10-16 21:34:46 -0700182 public void deactivate() {
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700183 componentConfigService.unregisterProperties(getClass(), false);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700184 deviceService.removeListener(deviceListener);
185 active = false;
186 controller.getNetconfDevices().forEach(id -> {
187 deviceKeyAdminService.removeKey(DeviceKeyId.deviceKeyId(id.toString()));
188 controller.disconnectDevice(id, true);
189 });
Andrea Campanella86294db2016-03-07 11:42:49 -0800190 controller.removeDeviceListener(innerNodeListener);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700191 deviceService.removeListener(deviceListener);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530192 providerRegistry.unregister(this);
193 providerService = null;
andreaeb70a942015-10-16 21:34:46 -0700194 cfgService.unregisterConfigFactory(factory);
helenyrwufd296b62016-06-22 17:43:02 -0700195 scheduledTask.cancel(true);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700196 executor.shutdown();
Sanjay Seb5eebb2015-04-24 15:44:50 +0530197 log.info("Stopped");
Sanjay Se8dcfee2015-04-23 10:07:08 +0530198 }
199
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700200
201 @Modified
202 public void modified(ComponentContext context) {
203 if (context != null) {
204 Dictionary<?, ?> properties = context.getProperties();
205 pollFrequency = Tools.getIntegerProperty(properties, "pollFrequency",
206 DEFAULT_POLL_FREQUENCY_SECONDS);
207 log.info("Configured. Poll frequency is configured to {} seconds", pollFrequency);
208 }
209 if (scheduledTask != null) {
210 scheduledTask.cancel(false);
211 }
212 scheduledTask = schedulePolling();
213 }
214
andreaeb70a942015-10-16 21:34:46 -0700215 public NetconfDeviceProvider() {
Andrea Campanella101417d2015-12-11 17:58:07 -0800216 super(new ProviderId(SCHEME_NAME, DEVICE_PROVIDER_PACKAGE));
Sanjay Se8dcfee2015-04-23 10:07:08 +0530217 }
218
helenyrwufd296b62016-06-22 17:43:02 -0700219 // Checks connection to devices in the config file
220 // every DEFAULT_POLL_FREQUENCY_SECONDS seconds.
221 private ScheduledFuture schedulePolling() {
Yuta HIGUCHIc2b82e32017-03-10 14:33:41 -0800222 return connectionExecutor.scheduleAtFixedRate(exceptionSafe(this::checkAndUpdateDevices),
Thomas Vachuskaf3aaa8d2017-03-31 10:43:58 -0700223 pollFrequency / 10,
224 pollFrequency, TimeUnit.SECONDS);
helenyrwufd296b62016-06-22 17:43:02 -0700225 }
226
Yuta HIGUCHIc2b82e32017-03-10 14:33:41 -0800227 private Runnable exceptionSafe(Runnable runnable) {
228 return new Runnable() {
229
230 @Override
231 public void run() {
232 try {
233 runnable.run();
234 } catch (Exception e) {
235 log.error("Unhandled Exception", e);
236 }
237 }
238 };
239 }
240
Sanjay Se8dcfee2015-04-23 10:07:08 +0530241 @Override
242 public void triggerProbe(DeviceId deviceId) {
andreaeb70a942015-10-16 21:34:46 -0700243 // TODO: This will be implemented later.
244 log.info("Triggering probe on device {}", deviceId);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530245 }
246
247 @Override
248 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700249 if (active) {
250 switch (newRole) {
251 case MASTER:
252 initiateConnection(deviceId, newRole);
253 log.debug("Accepting mastership role change to {} for device {}", newRole, deviceId);
254 break;
255 case STANDBY:
256 controller.disconnectDevice(deviceId, false);
257 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.STANDBY);
258 //else no-op
259 break;
260 case NONE:
261 controller.disconnectDevice(deviceId, false);
262 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.NONE);
263 break;
264 default:
265 log.error("Unimplemented Mastership state : {}", newRole);
266
267 }
268 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530269 }
270
271 @Override
272 public boolean isReachable(DeviceId deviceId) {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700273 //FIXME this is a workaround util device state is shared
274 // between controller instances.
275 Device device = deviceService.getDevice(deviceId);
276 String ip;
277 int port;
278 Socket socket = null;
279 if (device != null) {
280 ip = device.annotations().value(IPADDRESS);
281 port = Integer.parseInt(device.annotations().value(PORT));
282 } else {
283 String[] info = deviceId.toString().split(":");
284 if (info.length == 3) {
285 ip = info[1];
286 port = Integer.parseInt(info[2]);
287 } else {
288 ip = Arrays.asList(info).stream().filter(el -> !el.equals(info[0])
289 && !el.equals(info[info.length - 1]))
290 .reduce((t, u) -> t + ":" + u)
291 .get();
292 log.debug("ip v6 {}", ip);
293 port = Integer.parseInt(info[info.length - 1]);
294 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530295 }
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700296 //test connection to device opening a socket to it.
297 try {
298 socket = new Socket(ip, port);
Yuta HIGUCHI0454d702017-03-17 10:08:38 -0700299 log.debug("rechability of {}, {}, {}", deviceId, socket.isConnected(), !socket.isClosed());
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700300 return socket.isConnected() && !socket.isClosed();
301 } catch (IOException e) {
302 log.info("Device {} is not reachable", deviceId);
303 return false;
304 } finally {
305 if (socket != null) {
306 try {
307 socket.close();
308 } catch (IOException e) {
309 log.debug("Test Socket failed {} ", deviceId);
310 return false;
311 }
312 }
313 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530314 }
315
Saurav Dasa2d37502016-03-25 17:50:40 -0700316 @Override
317 public void changePortState(DeviceId deviceId, PortNumber portNumber,
318 boolean enable) {
319 // TODO if required
320 }
321
andreaeb70a942015-10-16 21:34:46 -0700322 private class InnerNetconfDeviceListener implements NetconfDeviceListener {
Sanjay Se8dcfee2015-04-23 10:07:08 +0530323
Andrea Campanella101417d2015-12-11 17:58:07 -0800324
andreaeb70a942015-10-16 21:34:46 -0700325 @Override
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700326 public void deviceAdded(DeviceId deviceId) {
327 //no-op
328 log.debug("Netconf device {} added to Netconf subController", deviceId);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530329 }
330
331 @Override
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700332 public void deviceRemoved(DeviceId deviceId) {
333 Preconditions.checkNotNull(deviceId, ISNULL);
helenyrwufd296b62016-06-22 17:43:02 -0700334
335 if (deviceService.getDevice(deviceId) != null) {
336 providerService.deviceDisconnected(deviceId);
337 log.debug("Netconf device {} removed from Netconf subController", deviceId);
338 } else {
339 log.warn("Netconf device {} does not exist in the store, " +
Vidyashree Ramad89a1532017-03-30 15:13:52 +0530340 "it may already have been removed", deviceId);
helenyrwufd296b62016-06-22 17:43:02 -0700341 }
andreaeb70a942015-10-16 21:34:46 -0700342 }
343 }
344
andreaeb70a942015-10-16 21:34:46 -0700345 private void connectDevices() {
346 NetconfProviderConfig cfg = cfgService.getConfig(appId, NetconfProviderConfig.class);
347 if (cfg != null) {
Sanjay Se8dcfee2015-04-23 10:07:08 +0530348 try {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700349 cfg.getDevicesAddresses().forEach(addr -> {
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700350 DeviceId deviceId = getDeviceId(addr.ip().toString(), addr.port());
351 Preconditions.checkNotNull(deviceId, ISNULL);
352 //Netconf configuration object
353 ChassisId cid = new ChassisId();
354 String ipAddress = addr.ip().toString();
355 SparseAnnotations annotations = DefaultAnnotations.builder()
356 .set(IPADDRESS, ipAddress)
357 .set(PORT, String.valueOf(addr.port()))
358 .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase())
359 .build();
360 DeviceDescription deviceDescription = new DefaultDeviceDescription(
361 deviceId.uri(),
362 Device.Type.SWITCH,
363 UNKNOWN, UNKNOWN,
364 UNKNOWN, UNKNOWN,
helenyrwufd296b62016-06-22 17:43:02 -0700365 cid, false,
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700366 annotations);
Himanshu Ranjan7c2ee3c2017-02-13 05:10:08 -0600367 storeDeviceKey(addr, deviceId);
368
helenyrwufd296b62016-06-22 17:43:02 -0700369 if (deviceService.getDevice(deviceId) == null) {
370 providerService.deviceConnected(deviceId, deviceDescription);
371 }
Yuta HIGUCHIc2b82e32017-03-10 14:33:41 -0800372 try {
373 checkAndUpdateDevice(deviceId, deviceDescription);
374 } catch (Exception e) {
375 log.error("Unhandled exception checking {}", deviceId, e);
376 }
helenyrwufd296b62016-06-22 17:43:02 -0700377 });
378 } catch (ConfigException e) {
379 log.error("Cannot read config error " + e);
380 }
381 }
382 }
383
384 private void checkAndUpdateDevice(DeviceId deviceId, DeviceDescription deviceDescription) {
Vidyashree Ramad89a1532017-03-30 15:13:52 +0530385 Device device = deviceService.getDevice(deviceId);
386 if (device == null) {
helenyrwufd296b62016-06-22 17:43:02 -0700387 log.warn("Device {} has not been added to store, " +
388 "maybe due to a problem in connectivity", deviceId);
389 } else {
390 boolean isReachable = isReachable(deviceId);
391 if (isReachable && !deviceService.isAvailable(deviceId)) {
Konstantinos Kanonakis4d67dd82016-08-05 12:18:52 -0500392 if (device.is(DeviceDescriptionDiscovery.class)) {
393 if (mastershipService.isLocalMaster(deviceId)) {
394 DeviceDescriptionDiscovery deviceDescriptionDiscovery =
395 device.as(DeviceDescriptionDiscovery.class);
Michele Santuari00cc1f72016-09-08 17:05:24 +0200396 DeviceDescription updatedDeviceDescription = deviceDescriptionDiscovery.discoverDeviceDetails();
397 if (updatedDeviceDescription != null &&
398 !descriptionEquals(device, updatedDeviceDescription)) {
399 providerService.deviceConnected(
400 deviceId, new DefaultDeviceDescription(
401 updatedDeviceDescription, true, updatedDeviceDescription.annotations()));
Michele Santuari576f09c2016-09-28 14:20:00 +0200402 } else if (updatedDeviceDescription == null) {
403 providerService.deviceConnected(
404 deviceId, new DefaultDeviceDescription(
405 deviceDescription, true, deviceDescription.annotations()));
Michele Santuari00cc1f72016-09-08 17:05:24 +0200406 }
407 //if ports are not discovered, retry the discovery
408 if (deviceService.getPorts(deviceId).isEmpty()) {
409 discoverPorts(deviceId);
410 }
Konstantinos Kanonakis4d67dd82016-08-05 12:18:52 -0500411 }
412 } else {
Michele Santuari576f09c2016-09-28 14:20:00 +0200413 log.warn("No DeviceDescriptionDiscovery behaviour for device {} " +
414 "using DefaultDeviceDescription", deviceId);
Vidyashree Ramad89a1532017-03-30 15:13:52 +0530415 providerService.deviceConnected(
416 deviceId, new DefaultDeviceDescription(
Michele Santuari576f09c2016-09-28 14:20:00 +0200417 deviceDescription, true, deviceDescription.annotations()));
Konstantinos Kanonakis4d67dd82016-08-05 12:18:52 -0500418 }
helenyrwufd296b62016-06-22 17:43:02 -0700419 } else if (!isReachable && deviceService.isAvailable(deviceId)) {
420 providerService.deviceDisconnected(deviceId);
Vidyashree Rama229554a2017-04-14 15:24:45 +0530421 } else if (isReachable && deviceService.isAvailable(deviceId) &&
422 mastershipService.isLocalMaster(deviceId)) {
Vidyashree Ramad89a1532017-03-30 15:13:52 +0530423 updatePortStatistics(device);
helenyrwufd296b62016-06-22 17:43:02 -0700424 }
425 }
426 }
427
Vidyashree Ramad89a1532017-03-30 15:13:52 +0530428 private void updatePortStatistics(Device device) {
429 if (device.is(PortStatisticsDiscovery.class)) {
430 PortStatisticsDiscovery d = device.as(PortStatisticsDiscovery.class);
Andrea Campanellac3627842017-04-04 18:06:54 +0200431 Collection<PortStatistics> portStatistics = d.discoverPortStatistics();
432 if (portStatistics != null) {
433 providerService.updatePortStatistics(device.id(),
434 portStatistics);
435 }
Vidyashree Ramad89a1532017-03-30 15:13:52 +0530436 } else {
437 log.warn("No port statistics getter behaviour for device {}",
438 device.id());
439 }
440 }
441
Michele Santuari00cc1f72016-09-08 17:05:24 +0200442 private boolean descriptionEquals(Device device, DeviceDescription updatedDeviceDescription) {
Yuta HIGUCHIf381fc72017-01-03 10:39:36 -0800443 return Objects.equal(device.id().uri(), updatedDeviceDescription.deviceUri())
Michele Santuari00cc1f72016-09-08 17:05:24 +0200444 && Objects.equal(device.type(), updatedDeviceDescription.type())
445 && Objects.equal(device.manufacturer(), updatedDeviceDescription.manufacturer())
446 && Objects.equal(device.hwVersion(), updatedDeviceDescription.hwVersion())
447 && Objects.equal(device.swVersion(), updatedDeviceDescription.swVersion())
448 && Objects.equal(device.serialNumber(), updatedDeviceDescription.serialNumber())
449 && Objects.equal(device.chassisId(), updatedDeviceDescription.chassisId())
450 && Objects.equal(device.annotations(), updatedDeviceDescription.annotations());
451 }
452
helenyrwufd296b62016-06-22 17:43:02 -0700453 private void checkAndUpdateDevices() {
454 NetconfProviderConfig cfg = cfgService.getConfig(appId, NetconfProviderConfig.class);
455 if (cfg != null) {
456 log.info("Checking connection to devices in configuration");
457 try {
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700458 cfg.getDevicesAddresses().forEach(addr -> {
helenyrwufd296b62016-06-22 17:43:02 -0700459 DeviceId deviceId = getDeviceId(addr.ip().toString(), addr.port());
460 Preconditions.checkNotNull(deviceId, ISNULL);
461 //Netconf configuration object
462 ChassisId cid = new ChassisId();
463 String ipAddress = addr.ip().toString();
464 SparseAnnotations annotations = DefaultAnnotations.builder()
465 .set(IPADDRESS, ipAddress)
466 .set(PORT, String.valueOf(addr.port()))
467 .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase())
468 .build();
469 DeviceDescription deviceDescription = new DefaultDeviceDescription(
470 deviceId.uri(),
471 Device.Type.SWITCH,
472 UNKNOWN, UNKNOWN,
473 UNKNOWN, UNKNOWN,
474 cid, false,
475 annotations);
Himanshu Ranjan7c2ee3c2017-02-13 05:10:08 -0600476 storeDeviceKey(addr, deviceId);
helenyrwufd296b62016-06-22 17:43:02 -0700477 checkAndUpdateDevice(deviceId, deviceDescription);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700478 });
andreaeb70a942015-10-16 21:34:46 -0700479 } catch (ConfigException e) {
480 log.error("Cannot read config error " + e);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530481 }
482 }
andreaeb70a942015-10-16 21:34:46 -0700483 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530484
Himanshu Ranjan7c2ee3c2017-02-13 05:10:08 -0600485 private void storeDeviceKey(NetconfProviderConfig.NetconfDeviceAddress addr, DeviceId deviceId) {
486 if (addr.sshkey().equals("")) {
487 deviceKeyAdminService.addKey(
488 DeviceKey.createDeviceKeyUsingUsernamePassword(
489 DeviceKeyId.deviceKeyId(deviceId.toString()),
490 null, addr.name(), addr.password()));
491 } else {
492 deviceKeyAdminService.addKey(
493 DeviceKey.createDeviceKeyUsingSshKey(
494 DeviceKeyId.deviceKeyId(deviceId.toString()),
495 null, addr.name(), addr.password(), addr.sshkey()));
496 }
497 }
498
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700499 private void initiateConnection(DeviceId deviceId, MastershipRole newRole) {
500 try {
501 if (isReachable(deviceId)) {
502 controller.connectDevice(deviceId);
503 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.MASTER);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700504 }
505 } catch (Exception e) {
506 if (deviceService.getDevice(deviceId) != null) {
507 providerService.deviceDisconnected(deviceId);
508 }
509 deviceKeyAdminService.removeKey(DeviceKeyId.deviceKeyId(deviceId.toString()));
510 throw new RuntimeException(new NetconfException(
511 "Can't connect to NETCONF " + "device on " + deviceId + ":" + deviceId, e));
512
513 }
514 }
515
516 private void discoverPorts(DeviceId deviceId) {
517 Device device = deviceService.getDevice(deviceId);
Andrea Campanella6c71a052016-04-22 11:56:31 -0700518 //TODO remove when PortDiscovery is removed from master
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700519 if (device.is(PortDiscovery.class)) {
520 PortDiscovery portConfig = device.as(PortDiscovery.class);
521 providerService.updatePorts(deviceId,
522 portConfig.getPorts());
Andrea Campanella6c71a052016-04-22 11:56:31 -0700523 } else if (device.is(DeviceDescriptionDiscovery.class)) {
524 DeviceDescriptionDiscovery deviceDescriptionDiscovery =
525 device.as(DeviceDescriptionDiscovery.class);
526 providerService.updatePorts(deviceId,
527 deviceDescriptionDiscovery.discoverPortDetails());
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700528 } else {
529 log.warn("No portGetter behaviour for device {}", deviceId);
530 }
Gaurav Agrawaldab4d772017-03-29 15:15:13 +0530531
532 // Port statistics discovery
Vidyashree Ramad89a1532017-03-30 15:13:52 +0530533 updatePortStatistics(device);
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700534 }
535
536 /**
537 * Return the DeviceId about the device containing the URI.
538 *
Andrea Campanella6c71a052016-04-22 11:56:31 -0700539 * @param ip IP address
Ray Milkeyd4334db2016-04-05 17:39:44 -0700540 * @param port port number
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700541 * @return DeviceId
542 */
543 public DeviceId getDeviceId(String ip, int port) {
544 try {
545 return DeviceId.deviceId(new URI(NETCONF, ip + ":" + port, null));
546 } catch (URISyntaxException e) {
547 throw new IllegalArgumentException("Unable to build deviceID for device "
548 + ip + ":" + port, e);
549 }
550 }
551
552 /**
553 * Listener for configuration events.
554 */
andreaeb70a942015-10-16 21:34:46 -0700555 private class InternalNetworkConfigListener implements NetworkConfigListener {
Sanjay Se8dcfee2015-04-23 10:07:08 +0530556
andreaeb70a942015-10-16 21:34:46 -0700557
558 @Override
559 public void event(NetworkConfigEvent event) {
Andrea Campanella90f044f2016-03-02 09:14:57 -0800560 executor.execute(NetconfDeviceProvider.this::connectDevices);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530561 }
562
andreaeb70a942015-10-16 21:34:46 -0700563 @Override
564 public boolean isRelevant(NetworkConfigEvent event) {
andreaeb70a942015-10-16 21:34:46 -0700565 return event.configClass().equals(NetconfProviderConfig.class) &&
566 (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
567 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED);
Sanjay Se8dcfee2015-04-23 10:07:08 +0530568 }
569 }
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700570
571 /**
572 * Listener for core device events.
573 */
574 private class InternalDeviceListener implements DeviceListener {
575 @Override
576 public void event(DeviceEvent event) {
577 if ((event.type() == DeviceEvent.Type.DEVICE_ADDED)) {
578 executor.execute(() -> discoverPorts(event.subject().id()));
579 } else if ((event.type() == DeviceEvent.Type.DEVICE_REMOVED)) {
580 log.debug("removing device {}", event.subject().id());
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700581 controller.disconnectDevice(event.subject().id(), true);
582 }
583 }
584
585 @Override
586 public boolean isRelevant(DeviceEvent event) {
587 if (mastershipService.getMasterFor(event.subject().id()) == null) {
588 return true;
589 }
Yuta HIGUCHI8c6a7e82017-03-14 18:35:43 -0700590 return SCHEME_NAME.toUpperCase()
591 .equals(event.subject().annotations().value(AnnotationKeys.PROTOCOL)) &&
Michele Santuari576f09c2016-09-28 14:20:00 +0200592 mastershipService.isLocalMaster(event.subject().id());
Andrea Campanella7e6200a2016-03-21 09:48:40 -0700593 }
594 }
Sanjay Se8dcfee2015-04-23 10:07:08 +0530595}