blob: 23f7ad26b5923a180e3b23ad4eafc91a3a3cb80b [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
Ray Milkeyd84f89b2018-08-17 14:54:17 -070018import org.osgi.service.component.annotations.Activate;
19import org.osgi.service.component.annotations.Component;
20import org.osgi.service.component.annotations.Deactivate;
21import org.osgi.service.component.annotations.Reference;
22import org.osgi.service.component.annotations.ReferenceCardinality;
Marc De Leenheer57a5af02016-12-02 20:54:41 -080023import org.onlab.packet.ChassisId;
24import org.onosproject.core.ApplicationId;
25import org.onosproject.core.CoreService;
Marc De Leenheer57a5af02016-12-02 20:54:41 -080026import org.onosproject.net.AnnotationKeys;
27import org.onosproject.net.DefaultAnnotations;
28import org.onosproject.net.Device;
29import org.onosproject.net.DeviceId;
30import org.onosproject.net.MastershipRole;
31import org.onosproject.net.PortNumber;
32import org.onosproject.net.SparseAnnotations;
33import org.onosproject.net.config.ConfigFactory;
34import org.onosproject.net.config.NetworkConfigEvent;
35import org.onosproject.net.config.NetworkConfigListener;
36import org.onosproject.net.config.NetworkConfigRegistry;
Andrea Campanella59b549d2017-04-14 21:58:16 +020037import org.onosproject.net.config.basics.SubjectFactories;
Marc De Leenheer57a5af02016-12-02 20:54:41 -080038import org.onosproject.net.device.DefaultDeviceDescription;
39import org.onosproject.net.device.DeviceAdminService;
40import org.onosproject.net.device.DeviceDescription;
41import org.onosproject.net.device.DeviceDescriptionDiscovery;
42import org.onosproject.net.device.DeviceProvider;
43import org.onosproject.net.device.DeviceProviderRegistry;
44import org.onosproject.net.device.DeviceProviderService;
45import org.onosproject.net.device.DeviceService;
46import org.onosproject.net.provider.AbstractProvider;
47import org.onosproject.net.provider.ProviderId;
Yuta HIGUCHIc6358352017-06-23 11:56:27 -070048import org.onosproject.tl1.DefaultTl1Device;
Marc De Leenheer57a5af02016-12-02 20:54:41 -080049import org.onosproject.tl1.Tl1Controller;
50import org.onosproject.tl1.Tl1Device;
51import org.onosproject.tl1.Tl1Listener;
Yuta HIGUCHIc6358352017-06-23 11:56:27 -070052import org.onosproject.tl1.device.Tl1DeviceConfig;
Marc De Leenheer57a5af02016-12-02 20:54:41 -080053import org.slf4j.Logger;
54
55import java.io.IOException;
56import java.net.InetSocketAddress;
57import java.net.Socket;
58import java.net.URI;
59import java.net.URISyntaxException;
60import java.util.NoSuchElementException;
Andrea Campanella59b549d2017-04-14 21:58:16 +020061import java.util.Set;
Marc De Leenheer57a5af02016-12-02 20:54:41 -080062
Marc De Leenheer57a5af02016-12-02 20:54:41 -080063import static org.slf4j.LoggerFactory.getLogger;
64
65/**
66 * Device provider for TL1 devices.
Andrea Campanella59b549d2017-04-14 21:58:16 +020067 * <p>
Marc De Leenheer57a5af02016-12-02 20:54:41 -080068 * Sits between ONOS provider service and the TL1 controller.
69 * Relies on network config subsystem to know about devices.
70 */
71@Component(immediate = true)
72public class Tl1DeviceProvider extends AbstractProvider implements DeviceProvider {
73 private static final String APP_NAME = "org.onosproject.tl1";
Marc De Leenheer57a5af02016-12-02 20:54:41 -080074 private static final String PROVIDER = "org.onosproject.provider.tl1.device";
75 private static final String UNKNOWN = "unknown";
76 private static final int REACHABILITY_TIMEOUT = 2000; // in milliseconds
77
78 private final Logger log = getLogger(getClass());
79
Ray Milkeyd84f89b2018-08-17 14:54:17 -070080 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Marc De Leenheer57a5af02016-12-02 20:54:41 -080081 protected NetworkConfigRegistry cfgRegistry;
82
Ray Milkeyd84f89b2018-08-17 14:54:17 -070083 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Marc De Leenheer57a5af02016-12-02 20:54:41 -080084 protected CoreService coreService;
85
Ray Milkeyd84f89b2018-08-17 14:54:17 -070086 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Marc De Leenheer57a5af02016-12-02 20:54:41 -080087 protected DeviceProviderRegistry providerRegistry;
88
Ray Milkeyd84f89b2018-08-17 14:54:17 -070089 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Marc De Leenheer57a5af02016-12-02 20:54:41 -080090 protected DeviceAdminService deviceAdminService;
91
Ray Milkeyd84f89b2018-08-17 14:54:17 -070092 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Marc De Leenheer57a5af02016-12-02 20:54:41 -080093 protected DeviceService deviceService;
94
Ray Milkeyd84f89b2018-08-17 14:54:17 -070095 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Marc De Leenheer57a5af02016-12-02 20:54:41 -080096 protected Tl1Controller controller;
97
98 private ApplicationId appId;
99 private NetworkConfigListener cfgListener = new InnerConfigListener();
100 private Tl1Listener tl1Listener = new InnerTl1Listener();
101 private DeviceProviderService providerService;
102
Ray Milkey5e82aa92018-02-13 13:18:42 -0800103 private final ConfigFactory factory =
Andrea Campanella59b549d2017-04-14 21:58:16 +0200104 new ConfigFactory<DeviceId, Tl1DeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
105 Tl1DeviceConfig.class,
Yuta HIGUCHIc6358352017-06-23 11:56:27 -0700106 Tl1DeviceConfig.TL1) {
Andrea Campanella59b549d2017-04-14 21:58:16 +0200107 @Override
108 public Tl1DeviceConfig createConfig() {
109 return new Tl1DeviceConfig();
110 }
Ray Milkey5e82aa92018-02-13 13:18:42 -0800111 };
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800112
113 @Activate
114 public void activate() {
115 appId = coreService.registerApplication(APP_NAME);
116 providerService = providerRegistry.register(this);
117 cfgRegistry.addListener(cfgListener);
118 controller.addListener(tl1Listener);
Ray Milkey5e82aa92018-02-13 13:18:42 -0800119 cfgRegistry.registerConfigFactory(factory);
Andrea Campanella59b549d2017-04-14 21:58:16 +0200120 connectDevices();
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800121 log.info("Started");
122 }
123
124 @Deactivate
125 public void deactivate() {
126 controller.removeListener(tl1Listener);
127 cfgRegistry.removeListener(cfgListener);
128 controller.getDeviceIds().forEach(deviceId -> {
129 controller.removeDevice(deviceId);
130 deviceAdminService.removeDevice(deviceId);
131 });
132 providerRegistry.unregister(this);
Ray Milkey5e82aa92018-02-13 13:18:42 -0800133 cfgRegistry.unregisterConfigFactory(factory);
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800134 providerService = null;
135 log.info("Stopped");
136 }
137
138 public Tl1DeviceProvider() {
Yuta HIGUCHIc6358352017-06-23 11:56:27 -0700139 super(new ProviderId(Tl1DeviceConfig.TL1, PROVIDER));
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800140 }
141
Yuta HIGUCHI08057cb2017-03-06 10:07:06 -0800142 @Override
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800143 public void triggerProbe(DeviceId deviceId) {
144 // TODO
145 }
146
Yuta HIGUCHI08057cb2017-03-06 10:07:06 -0800147 @Override
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800148 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
149 switch (newRole) {
150 case MASTER:
151 controller.connectDevice(deviceId);
152 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.MASTER);
153 log.debug("Accepting mastership role change to {} for device {}", newRole, deviceId);
154 break;
155 case STANDBY:
156 controller.disconnectDevice(deviceId);
157 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.STANDBY);
158 break;
159 case NONE:
160 controller.disconnectDevice(deviceId);
161 providerService.receivedRoleReply(deviceId, newRole, MastershipRole.NONE);
162 break;
163 default:
164 log.error("Invalid mastership state: {}", newRole);
165 }
166 }
167
168 // Assumes device is registered in TL1 controller.
Yuta HIGUCHI08057cb2017-03-06 10:07:06 -0800169 @Override
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800170 public boolean isReachable(DeviceId deviceId) {
171 try {
172 // First check if device is already connected.
173 // If not, try to open a socket.
174 Tl1Device device = controller.getDevice(deviceId).get();
175 if (device.isConnected()) {
176 return true;
177 }
178
179 Socket socket = new Socket();
180 socket.connect(new InetSocketAddress(device.ip().toInetAddress(), device.port()), REACHABILITY_TIMEOUT);
181 socket.close();
182 return true;
183 } catch (NoSuchElementException | IOException | IllegalArgumentException e) {
184 log.error("Cannot reach device {}", deviceId, e);
185 return false;
186 }
187 }
188
Yuta HIGUCHI08057cb2017-03-06 10:07:06 -0800189 @Override
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800190 public void changePortState(DeviceId deviceId, PortNumber portNumber, boolean enable) {
191 // TODO
192 }
193
Andrea Campanella59b549d2017-04-14 21:58:16 +0200194 //Method to register devices provided via net-cfg under devices/ tree
195 private void connectDevices() {
196 Set<DeviceId> deviceSubjects =
197 cfgRegistry.getSubjects(DeviceId.class, Tl1DeviceConfig.class);
198 deviceSubjects.forEach(deviceId -> {
199 Tl1DeviceConfig config =
200 cfgRegistry.getConfig(deviceId, Tl1DeviceConfig.class);
201 connectDevice(new DefaultTl1Device(config.ip(), config.port(), config.username(),
202 config.password()));
203 });
204 }
205
206 // Register a device in the core and in the TL1 controller.
207 private void connectDevice(Tl1Device device) {
208 try {
209 // Add device to TL1 controller
210 DeviceId deviceId = DeviceId.deviceId(
Yuta HIGUCHIc6358352017-06-23 11:56:27 -0700211 new URI(Tl1DeviceConfig.TL1, device.ip() + ":" + device.port(), null));
Andrea Campanella59b549d2017-04-14 21:58:16 +0200212
213 if (controller.addDevice(deviceId, device)) {
214 SparseAnnotations ann = DefaultAnnotations.builder()
Yuta HIGUCHIc6358352017-06-23 11:56:27 -0700215 .set(AnnotationKeys.PROTOCOL, Tl1DeviceConfig.TL1.toUpperCase())
Andrea Campanella59b549d2017-04-14 21:58:16 +0200216 .build();
217 // Register device in the core with default parameters and mark it as unavailable
218 DeviceDescription dd = new DefaultDeviceDescription(deviceId.uri(),
219 Device.Type.SWITCH,
220 UNKNOWN, UNKNOWN,
221 UNKNOWN, UNKNOWN,
222 new ChassisId(),
223 false, ann);
224 providerService.deviceConnected(deviceId, dd);
225 }
226 } catch (URISyntaxException e) {
227 log.error("Skipping device {}", device, e);
228 }
229 }
230
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800231 /**
232 * Tries to update the device and port descriptions through the {@code DeviceDescriptionDiscovery} behaviour.
233 *
234 * @param deviceId the device
235 */
236 void updateDevice(DeviceId deviceId) {
237 Device device = deviceService.getDevice(deviceId);
238
239 if (!device.is(DeviceDescriptionDiscovery.class)) {
240 return;
241 }
242
243 try {
244 // Update device description
245 DeviceDescriptionDiscovery discovery = device.as(DeviceDescriptionDiscovery.class);
246 DeviceDescription dd = discovery.discoverDeviceDetails();
247 if (dd == null) {
248 return;
249 }
250 providerService.deviceConnected(deviceId,
Andrea Campanella59b549d2017-04-14 21:58:16 +0200251 new DefaultDeviceDescription(dd, true, dd.annotations()));
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800252 // Update ports
253 providerService.updatePorts(deviceId, discovery.discoverPortDetails());
254 } catch (IllegalStateException | IllegalArgumentException e) {
255 log.error("Cannot update device description {}", deviceId, e);
256 }
257 }
258
259 /**
260 * Listener for network configuration events.
261 */
262 private class InnerConfigListener implements NetworkConfigListener {
Yuta HIGUCHI08057cb2017-03-06 10:07:06 -0800263 @Override
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800264 public void event(NetworkConfigEvent event) {
265 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
Andrea Campanella59b549d2017-04-14 21:58:16 +0200266 if (event.configClass().equals(Tl1DeviceConfig.class)) {
267 connectDevices();
268 } else {
269 log.warn("Injecting device via this Json is deprecated, " +
270 "please put configuration under devices/");
Andrea Campanella59b549d2017-04-14 21:58:16 +0200271 }
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800272 } else if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
273 // TODO: calculate delta
Andrea Campanella59b549d2017-04-14 21:58:16 +0200274 if (event.configClass().equals(Tl1DeviceConfig.class)) {
275 connectDevices();
276 } else {
277 log.warn("Injecting device via this Json is deprecated, " +
278 "please put configuration under devices/");
Andrea Campanella59b549d2017-04-14 21:58:16 +0200279 }
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800280 } else if (event.type() == NetworkConfigEvent.Type.CONFIG_REMOVED) {
281 controller.getDeviceIds().forEach(deviceId -> {
282 controller.removeDevice(deviceId);
283 deviceAdminService.removeDevice(deviceId);
284 });
285 }
286 }
287
Yuta HIGUCHI08057cb2017-03-06 10:07:06 -0800288 @Override
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800289 public boolean isRelevant(NetworkConfigEvent event) {
Ray Milkey5e82aa92018-02-13 13:18:42 -0800290 return (event.configClass().equals(Tl1DeviceConfig.class)) &&
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800291 (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
292 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED ||
293 event.type() == NetworkConfigEvent.Type.CONFIG_REMOVED);
294 }
295 }
296
297 /**
298 * Listener for TL1 events.
299 */
300 private class InnerTl1Listener implements Tl1Listener {
301 @Override
302 public void deviceConnected(DeviceId deviceId) {
303 updateDevice(deviceId);
304 }
305
306 @Override
307 public void deviceDisconnected(DeviceId deviceId) {
308 providerService.deviceDisconnected(deviceId);
309 }
310 }
311}