blob: e6f5e0bee89cb891b2d4a8eb64c59093d98e202d [file] [log] [blame]
Marc De Leenheer57a5af02016-12-02 20:54:41 -08001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
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
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
23import org.onlab.packet.ChassisId;
24import org.onosproject.core.ApplicationId;
25import org.onosproject.core.CoreService;
26import org.onosproject.incubator.net.config.basics.ConfigException;
27import org.onosproject.net.AnnotationKeys;
28import org.onosproject.net.DefaultAnnotations;
29import org.onosproject.net.Device;
30import org.onosproject.net.DeviceId;
31import org.onosproject.net.MastershipRole;
32import org.onosproject.net.PortNumber;
33import org.onosproject.net.SparseAnnotations;
34import org.onosproject.net.config.ConfigFactory;
35import org.onosproject.net.config.NetworkConfigEvent;
36import org.onosproject.net.config.NetworkConfigListener;
37import org.onosproject.net.config.NetworkConfigRegistry;
38import 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;
48import org.onosproject.tl1.Tl1Controller;
49import org.onosproject.tl1.Tl1Device;
50import org.onosproject.tl1.Tl1Listener;
51import org.slf4j.Logger;
52
53import java.io.IOException;
54import java.net.InetSocketAddress;
55import java.net.Socket;
56import java.net.URI;
57import java.net.URISyntaxException;
58import java.util.NoSuchElementException;
59
60import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
61import static org.slf4j.LoggerFactory.getLogger;
62
63/**
64 * Device provider for TL1 devices.
65 *
66 * Sits between ONOS provider service and the TL1 controller.
67 * Relies on network config subsystem to know about devices.
68 */
69@Component(immediate = true)
70public class Tl1DeviceProvider extends AbstractProvider implements DeviceProvider {
71 private static final String APP_NAME = "org.onosproject.tl1";
72 private static final String TL1 = "tl1";
73 private static final String PROVIDER = "org.onosproject.provider.tl1.device";
74 private static final String UNKNOWN = "unknown";
75 private static final int REACHABILITY_TIMEOUT = 2000; // in milliseconds
76
77 private final Logger log = getLogger(getClass());
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected NetworkConfigRegistry cfgRegistry;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected CoreService coreService;
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected DeviceProviderRegistry providerRegistry;
87
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected DeviceAdminService deviceAdminService;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected DeviceService deviceService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected Tl1Controller controller;
96
97 private ApplicationId appId;
98 private NetworkConfigListener cfgListener = new InnerConfigListener();
99 private Tl1Listener tl1Listener = new InnerTl1Listener();
100 private DeviceProviderService providerService;
101
102 private final ConfigFactory cfgFactory =
103 new ConfigFactory<ApplicationId, Tl1ProviderConfig>(APP_SUBJECT_FACTORY,
104 Tl1ProviderConfig.class,
Yuta HIGUCHI08057cb2017-03-06 10:07:06 -0800105 "tl1_devices",
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800106 true) {
107 @Override
108 public Tl1ProviderConfig createConfig() {
109 return new Tl1ProviderConfig();
110 }
111 };
112
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);
119 cfgRegistry.registerConfigFactory(cfgFactory);
120 registerDevices();
121 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);
133 cfgRegistry.unregisterConfigFactory(cfgFactory);
134 providerService = null;
135 log.info("Stopped");
136 }
137
138 public Tl1DeviceProvider() {
139 super(new ProviderId(TL1, PROVIDER));
140 }
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
194 // Register all devices in the core and in the TL1 controller
195 void registerDevices() {
196 Tl1ProviderConfig cfg = cfgRegistry.getConfig(appId, Tl1ProviderConfig.class);
197
198 if (cfg == null) {
199 return;
200 }
201
202 try {
203 cfg.readDevices().forEach(device -> {
204 try {
205 // Add device to TL1 controller
206 DeviceId deviceId = DeviceId.deviceId(
207 new URI(TL1, device.ip() + ":" + device.port(), null));
208
209 if (controller.addDevice(deviceId, device)) {
210 SparseAnnotations ann = DefaultAnnotations.builder()
211 .set(AnnotationKeys.PROTOCOL, TL1.toUpperCase())
212 .build();
213 // Register device in the core with default parameters and mark it as unavailable
214 DeviceDescription dd = new DefaultDeviceDescription(deviceId.uri(), Device.Type.SWITCH, UNKNOWN,
215 UNKNOWN, UNKNOWN, UNKNOWN, new ChassisId(), false, ann);
216 providerService.deviceConnected(deviceId, dd);
217 }
218 } catch (URISyntaxException e) {
219 log.error("Skipping device {}", device, e);
220 }
221 });
222 } catch (ConfigException e) {
223 log.error("Cannot parse network configuration", e);
224 }
225 }
226
227 /**
228 * Tries to update the device and port descriptions through the {@code DeviceDescriptionDiscovery} behaviour.
229 *
230 * @param deviceId the device
231 */
232 void updateDevice(DeviceId deviceId) {
233 Device device = deviceService.getDevice(deviceId);
234
235 if (!device.is(DeviceDescriptionDiscovery.class)) {
236 return;
237 }
238
239 try {
240 // Update device description
241 DeviceDescriptionDiscovery discovery = device.as(DeviceDescriptionDiscovery.class);
242 DeviceDescription dd = discovery.discoverDeviceDetails();
243 if (dd == null) {
244 return;
245 }
246 providerService.deviceConnected(deviceId,
247 new DefaultDeviceDescription(dd, true, dd.annotations()));
248 // Update ports
249 providerService.updatePorts(deviceId, discovery.discoverPortDetails());
250 } catch (IllegalStateException | IllegalArgumentException e) {
251 log.error("Cannot update device description {}", deviceId, e);
252 }
253 }
254
255 /**
256 * Listener for network configuration events.
257 */
258 private class InnerConfigListener implements NetworkConfigListener {
Yuta HIGUCHI08057cb2017-03-06 10:07:06 -0800259 @Override
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800260 public void event(NetworkConfigEvent event) {
261 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
262 registerDevices();
263 } else if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) {
264 // TODO: calculate delta
265 registerDevices();
266 } else if (event.type() == NetworkConfigEvent.Type.CONFIG_REMOVED) {
267 controller.getDeviceIds().forEach(deviceId -> {
268 controller.removeDevice(deviceId);
269 deviceAdminService.removeDevice(deviceId);
270 });
271 }
272 }
273
Yuta HIGUCHI08057cb2017-03-06 10:07:06 -0800274 @Override
Marc De Leenheer57a5af02016-12-02 20:54:41 -0800275 public boolean isRelevant(NetworkConfigEvent event) {
276 return event.configClass().equals(Tl1ProviderConfig.class) &&
277 (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
278 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED ||
279 event.type() == NetworkConfigEvent.Type.CONFIG_REMOVED);
280 }
281 }
282
283 /**
284 * Listener for TL1 events.
285 */
286 private class InnerTl1Listener implements Tl1Listener {
287 @Override
288 public void deviceConnected(DeviceId deviceId) {
289 updateDevice(deviceId);
290 }
291
292 @Override
293 public void deviceDisconnected(DeviceId deviceId) {
294 providerService.deviceDisconnected(deviceId);
295 }
296 }
297}