blob: e97043a002a3f47087a58dc849998280e6bd46b1 [file] [log] [blame]
Marc De Leenheer57a5af02016-12-02 20:54:41 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Marc De Leenheer57a5af02016-12-02 20:54:41 -08003 *
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 */
16package org.onosproject.provider.tl1.device.impl;
17
Andrea Campanella59b549d2017-04-14 21:58:16 +020018import com.google.common.collect.ImmutableList;
Marc De Leenheer57a5af02016-12-02 20:54:41 -080019import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.onlab.packet.ChassisId;
25import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
27import org.onosproject.incubator.net.config.basics.ConfigException;
28import org.onosproject.net.AnnotationKeys;
29import org.onosproject.net.DefaultAnnotations;
30import org.onosproject.net.Device;
31import org.onosproject.net.DeviceId;
32import org.onosproject.net.MastershipRole;
33import org.onosproject.net.PortNumber;
34import org.onosproject.net.SparseAnnotations;
35import org.onosproject.net.config.ConfigFactory;
36import org.onosproject.net.config.NetworkConfigEvent;
37import org.onosproject.net.config.NetworkConfigListener;
38import org.onosproject.net.config.NetworkConfigRegistry;
Andrea Campanella59b549d2017-04-14 21:58:16 +020039import org.onosproject.net.config.basics.SubjectFactories;
Marc De Leenheer57a5af02016-12-02 20:54:41 -080040import org.onosproject.net.device.DefaultDeviceDescription;
41import org.onosproject.net.device.DeviceAdminService;
42import org.onosproject.net.device.DeviceDescription;
43import org.onosproject.net.device.DeviceDescriptionDiscovery;
44import org.onosproject.net.device.DeviceProvider;
45import org.onosproject.net.device.DeviceProviderRegistry;
46import org.onosproject.net.device.DeviceProviderService;
47import org.onosproject.net.device.DeviceService;
48import org.onosproject.net.provider.AbstractProvider;
49import org.onosproject.net.provider.ProviderId;
Yuta HIGUCHIc6358352017-06-23 11:56:27 -070050import org.onosproject.tl1.DefaultTl1Device;
Marc De Leenheer57a5af02016-12-02 20:54:41 -080051import org.onosproject.tl1.Tl1Controller;
52import org.onosproject.tl1.Tl1Device;
53import org.onosproject.tl1.Tl1Listener;
Yuta HIGUCHIc6358352017-06-23 11:56:27 -070054import org.onosproject.tl1.device.Tl1DeviceConfig;
Marc De Leenheer57a5af02016-12-02 20:54:41 -080055import org.slf4j.Logger;
56
57import java.io.IOException;
58import java.net.InetSocketAddress;
59import java.net.Socket;
60import java.net.URI;
61import java.net.URISyntaxException;
Andrea Campanella59b549d2017-04-14 21:58:16 +020062import java.util.List;
Marc De Leenheer57a5af02016-12-02 20:54:41 -080063import java.util.NoSuchElementException;
Andrea Campanella59b549d2017-04-14 21:58:16 +020064import java.util.Set;
Marc De Leenheer57a5af02016-12-02 20:54:41 -080065
66import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
67import static org.slf4j.LoggerFactory.getLogger;
68
69/**
70 * Device provider for TL1 devices.
Andrea Campanella59b549d2017-04-14 21:58:16 +020071 * <p>
Marc De Leenheer57a5af02016-12-02 20:54:41 -080072 * Sits between ONOS provider service and the TL1 controller.
73 * Relies on network config subsystem to know about devices.
74 */
75@Component(immediate = true)
76public class Tl1DeviceProvider extends AbstractProvider implements DeviceProvider {
77 private static final String APP_NAME = "org.onosproject.tl1";
Yuta HIGUCHIc6358352017-06-23 11:56:27 -070078 /**
79 * @deprecated in 1.11.0. Use {@link Tl1DeviceConfig#TL1} instead
80 */
81 @Deprecated
82 protected static final String TL1 = Tl1DeviceConfig.TL1;
Marc De Leenheer57a5af02016-12-02 20:54:41 -080083 private static final String PROVIDER = "org.onosproject.provider.tl1.device";
84 private static final String UNKNOWN = "unknown";
85 private static final int REACHABILITY_TIMEOUT = 2000; // in milliseconds
86
87 private final Logger log = getLogger(getClass());
88
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected NetworkConfigRegistry cfgRegistry;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected CoreService coreService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected DeviceProviderRegistry providerRegistry;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected DeviceAdminService deviceAdminService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected DeviceService deviceService;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected Tl1Controller controller;
106
107 private ApplicationId appId;
108 private NetworkConfigListener cfgListener = new InnerConfigListener();
109 private Tl1Listener tl1Listener = new InnerTl1Listener();
110 private DeviceProviderService providerService;
111
Andrea Campanella59b549d2017-04-14 21:58:16 +0200112 private final List<ConfigFactory> factories = ImmutableList.of(
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800113 new ConfigFactory<ApplicationId, Tl1ProviderConfig>(APP_SUBJECT_FACTORY,
Andrea Campanella59b549d2017-04-14 21:58:16 +0200114 Tl1ProviderConfig.class,
115 "tl1_devices",
116 true) {
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800117 @Override
118 public Tl1ProviderConfig createConfig() {
119 return new Tl1ProviderConfig();
120 }
Andrea Campanella59b549d2017-04-14 21:58:16 +0200121 },
122 new ConfigFactory<DeviceId, Tl1DeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
123 Tl1DeviceConfig.class,
Yuta HIGUCHIc6358352017-06-23 11:56:27 -0700124 Tl1DeviceConfig.TL1) {
Andrea Campanella59b549d2017-04-14 21:58:16 +0200125 @Override
126 public Tl1DeviceConfig createConfig() {
127 return new Tl1DeviceConfig();
128 }
129 });
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800130
131 @Activate
132 public void activate() {
133 appId = coreService.registerApplication(APP_NAME);
134 providerService = providerRegistry.register(this);
135 cfgRegistry.addListener(cfgListener);
136 controller.addListener(tl1Listener);
Andrea Campanella59b549d2017-04-14 21:58:16 +0200137 factories.forEach(cfgRegistry::registerConfigFactory);
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800138 registerDevices();
Andrea Campanella59b549d2017-04-14 21:58:16 +0200139 connectDevices();
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800140 log.info("Started");
141 }
142
143 @Deactivate
144 public void deactivate() {
145 controller.removeListener(tl1Listener);
146 cfgRegistry.removeListener(cfgListener);
147 controller.getDeviceIds().forEach(deviceId -> {
148 controller.removeDevice(deviceId);
149 deviceAdminService.removeDevice(deviceId);
150 });
151 providerRegistry.unregister(this);
Andrea Campanella59b549d2017-04-14 21:58:16 +0200152 factories.forEach(cfgRegistry::unregisterConfigFactory);
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800153 providerService = null;
154 log.info("Stopped");
155 }
156
157 public Tl1DeviceProvider() {
Yuta HIGUCHIc6358352017-06-23 11:56:27 -0700158 super(new ProviderId(Tl1DeviceConfig.TL1, PROVIDER));
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800159 }
160
Yuta HIGUCHI08057cb2017-03-06 10:07:06 -0800161 @Override
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800162 public void triggerProbe(DeviceId deviceId) {
163 // TODO
164 }
165
Yuta HIGUCHI08057cb2017-03-06 10:07:06 -0800166 @Override
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800167 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
168 switch (newRole) {
169 case MASTER:
170 controller.connectDevice(deviceId);
171 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.MASTER);
172 log.debug("Accepting mastership role change to {} for device {}", newRole, deviceId);
173 break;
174 case STANDBY:
175 controller.disconnectDevice(deviceId);
176 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.STANDBY);
177 break;
178 case NONE:
179 controller.disconnectDevice(deviceId);
180 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.NONE);
181 break;
182 default:
183 log.error("Invalid mastership state: {}", newRole);
184 }
185 }
186
187 // Assumes device is registered in TL1 controller.
Yuta HIGUCHI08057cb2017-03-06 10:07:06 -0800188 @Override
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800189 public boolean isReachable(DeviceId deviceId) {
190 try {
191 // First check if device is already connected.
192 // If not, try to open a socket.
193 Tl1Device device = controller.getDevice(deviceId).get();
194 if (device.isConnected()) {
195 return true;
196 }
197
198 Socket socket = new Socket();
199 socket.connect(new InetSocketAddress(device.ip().toInetAddress(), device.port()), REACHABILITY_TIMEOUT);
200 socket.close();
201 return true;
202 } catch (NoSuchElementException | IOException | IllegalArgumentException e) {
203 log.error("Cannot reach device {}", deviceId, e);
204 return false;
205 }
206 }
207
Yuta HIGUCHI08057cb2017-03-06 10:07:06 -0800208 @Override
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800209 public void changePortState(DeviceId deviceId, PortNumber portNumber, boolean enable) {
210 // TODO
211 }
212
Andrea Campanella59b549d2017-04-14 21:58:16 +0200213 //Old method to register devices provided via net-cfg under apps/tl1/ tree
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800214 void registerDevices() {
215 Tl1ProviderConfig cfg = cfgRegistry.getConfig(appId, Tl1ProviderConfig.class);
216
217 if (cfg == null) {
218 return;
219 }
220
221 try {
Andrea Campanella59b549d2017-04-14 21:58:16 +0200222 cfg.readDevices().forEach(this::connectDevice);
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800223 } catch (ConfigException e) {
224 log.error("Cannot parse network configuration", e);
225 }
226 }
227
Andrea Campanella59b549d2017-04-14 21:58:16 +0200228 //Method to register devices provided via net-cfg under devices/ tree
229 private void connectDevices() {
230 Set<DeviceId> deviceSubjects =
231 cfgRegistry.getSubjects(DeviceId.class, Tl1DeviceConfig.class);
232 deviceSubjects.forEach(deviceId -> {
233 Tl1DeviceConfig config =
234 cfgRegistry.getConfig(deviceId, Tl1DeviceConfig.class);
235 connectDevice(new DefaultTl1Device(config.ip(), config.port(), config.username(),
236 config.password()));
237 });
238 }
239
240 // Register a device in the core and in the TL1 controller.
241 private void connectDevice(Tl1Device device) {
242 try {
243 // Add device to TL1 controller
244 DeviceId deviceId = DeviceId.deviceId(
Yuta HIGUCHIc6358352017-06-23 11:56:27 -0700245 new URI(Tl1DeviceConfig.TL1, device.ip() + ":" + device.port(), null));
Andrea Campanella59b549d2017-04-14 21:58:16 +0200246
247 if (controller.addDevice(deviceId, device)) {
248 SparseAnnotations ann = DefaultAnnotations.builder()
Yuta HIGUCHIc6358352017-06-23 11:56:27 -0700249 .set(AnnotationKeys.PROTOCOL, Tl1DeviceConfig.TL1.toUpperCase())
Andrea Campanella59b549d2017-04-14 21:58:16 +0200250 .build();
251 // Register device in the core with default parameters and mark it as unavailable
252 DeviceDescription dd = new DefaultDeviceDescription(deviceId.uri(),
253 Device.Type.SWITCH,
254 UNKNOWN, UNKNOWN,
255 UNKNOWN, UNKNOWN,
256 new ChassisId(),
257 false, ann);
258 providerService.deviceConnected(deviceId, dd);
259 }
260 } catch (URISyntaxException e) {
261 log.error("Skipping device {}", device, e);
262 }
263 }
264
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800265 /**
266 * Tries to update the device and port descriptions through the {@code DeviceDescriptionDiscovery} behaviour.
267 *
268 * @param deviceId the device
269 */
270 void updateDevice(DeviceId deviceId) {
271 Device device = deviceService.getDevice(deviceId);
272
273 if (!device.is(DeviceDescriptionDiscovery.class)) {
274 return;
275 }
276
277 try {
278 // Update device description
279 DeviceDescriptionDiscovery discovery = device.as(DeviceDescriptionDiscovery.class);
280 DeviceDescription dd = discovery.discoverDeviceDetails();
281 if (dd == null) {
282 return;
283 }
284 providerService.deviceConnected(deviceId,
Andrea Campanella59b549d2017-04-14 21:58:16 +0200285 new DefaultDeviceDescription(dd, true, dd.annotations()));
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800286 // Update ports
287 providerService.updatePorts(deviceId, discovery.discoverPortDetails());
288 } catch (IllegalStateException | IllegalArgumentException e) {
289 log.error("Cannot update device description {}", deviceId, e);
290 }
291 }
292
293 /**
294 * Listener for network configuration events.
295 */
296 private class InnerConfigListener implements NetworkConfigListener {
Yuta HIGUCHI08057cb2017-03-06 10:07:06 -0800297 @Override
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800298 public void event(NetworkConfigEvent event) {
299 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
Andrea Campanella59b549d2017-04-14 21:58:16 +0200300 if (event.configClass().equals(Tl1DeviceConfig.class)) {
301 connectDevices();
302 } else {
303 log.warn("Injecting device via this Json is deprecated, " +
304 "please put configuration under devices/");
305 registerDevices();
306 }
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800307 } else if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
308 // TODO: calculate delta
Andrea Campanella59b549d2017-04-14 21:58:16 +0200309 if (event.configClass().equals(Tl1DeviceConfig.class)) {
310 connectDevices();
311 } else {
312 log.warn("Injecting device via this Json is deprecated, " +
313 "please put configuration under devices/");
314 registerDevices();
315 }
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800316 } else if (event.type() == NetworkConfigEvent.Type.CONFIG_REMOVED) {
317 controller.getDeviceIds().forEach(deviceId -> {
318 controller.removeDevice(deviceId);
319 deviceAdminService.removeDevice(deviceId);
320 });
321 }
322 }
323
Yuta HIGUCHI08057cb2017-03-06 10:07:06 -0800324 @Override
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800325 public boolean isRelevant(NetworkConfigEvent event) {
Andrea Campanella59b549d2017-04-14 21:58:16 +0200326 return (event.configClass().equals(Tl1DeviceConfig.class) ||
327 event.configClass().equals(Tl1ProviderConfig.class)) &&
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800328 (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
329 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED ||
330 event.type() == NetworkConfigEvent.Type.CONFIG_REMOVED);
331 }
332 }
333
334 /**
335 * Listener for TL1 events.
336 */
337 private class InnerTl1Listener implements Tl1Listener {
338 @Override
339 public void deviceConnected(DeviceId deviceId) {
340 updateDevice(deviceId);
341 }
342
343 @Override
344 public void deviceDisconnected(DeviceId deviceId) {
345 providerService.deviceDisconnected(deviceId);
346 }
347 }
348}