blob: 5fbf3044f9454912761cab3389b62d3c240b2c7e [file] [log] [blame]
YuanyouZhangb5e05302015-07-21 20:14:35 +08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
YuanyouZhangb5e05302015-07-21 20:14:35 +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.ovsdb.providers.device;
17
YuanyouZhangb5e05302015-07-21 20:14:35 +080018import org.onlab.packet.ChassisId;
jiangrui83563612015-11-16 11:59:47 +080019import org.onlab.packet.IpAddress;
Michal Mach958adf62017-06-05 16:29:13 +020020import org.onosproject.mastership.MastershipService;
YuanyouZhangb5e05302015-07-21 20:14:35 +080021import org.onosproject.net.DefaultAnnotations;
22import org.onosproject.net.Device;
23import org.onosproject.net.DeviceId;
24import org.onosproject.net.MastershipRole;
Saurav Dasa2d37502016-03-25 17:50:40 -070025import org.onosproject.net.PortNumber;
YuanyouZhangb5e05302015-07-21 20:14:35 +080026import org.onosproject.net.SparseAnnotations;
27import org.onosproject.net.device.DefaultDeviceDescription;
28import org.onosproject.net.device.DeviceDescription;
Michal Mach958adf62017-06-05 16:29:13 +020029import org.onosproject.net.device.DeviceDescriptionDiscovery;
30import org.onosproject.net.device.DeviceEvent;
31import org.onosproject.net.device.DeviceListener;
YuanyouZhangb5e05302015-07-21 20:14:35 +080032import org.onosproject.net.device.DeviceProvider;
33import org.onosproject.net.device.DeviceProviderRegistry;
34import org.onosproject.net.device.DeviceProviderService;
Michal Mach958adf62017-06-05 16:29:13 +020035import org.onosproject.net.device.DeviceService;
YuanyouZhangb5e05302015-07-21 20:14:35 +080036import org.onosproject.net.provider.AbstractProvider;
37import org.onosproject.net.provider.ProviderId;
jiangrui83563612015-11-16 11:59:47 +080038import org.onosproject.ovsdb.controller.OvsdbClientService;
YuanyouZhangb5e05302015-07-21 20:14:35 +080039import org.onosproject.ovsdb.controller.OvsdbController;
40import org.onosproject.ovsdb.controller.OvsdbNodeId;
41import org.onosproject.ovsdb.controller.OvsdbNodeListener;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070042import org.osgi.service.component.annotations.Activate;
43import org.osgi.service.component.annotations.Component;
44import org.osgi.service.component.annotations.Deactivate;
45import org.osgi.service.component.annotations.Reference;
46import org.osgi.service.component.annotations.ReferenceCardinality;
YuanyouZhangb5e05302015-07-21 20:14:35 +080047import org.slf4j.Logger;
48
Ray Milkeyd84f89b2018-08-17 14:54:17 -070049import java.net.URI;
50import java.util.concurrent.ExecutorService;
51import java.util.concurrent.Executors;
52import java.util.concurrent.TimeUnit;
53
54import static com.google.common.base.Preconditions.checkNotNull;
55import static org.onlab.util.Tools.groupedThreads;
56import static org.slf4j.LoggerFactory.getLogger;
57
YuanyouZhangb5e05302015-07-21 20:14:35 +080058/**
59 * Provider which uses an ovsdb controller to detect device.
60 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070061@Component(immediate = true, service = DeviceProvider.class)
YuanyouZhangb5e05302015-07-21 20:14:35 +080062public class OvsdbDeviceProvider extends AbstractProvider
63 implements DeviceProvider {
64 private final Logger log = getLogger(getClass());
65
Ray Milkeyd84f89b2018-08-17 14:54:17 -070066 @Reference(cardinality = ReferenceCardinality.MANDATORY)
YuanyouZhangb5e05302015-07-21 20:14:35 +080067 protected DeviceProviderRegistry providerRegistry;
68
Ray Milkeyd84f89b2018-08-17 14:54:17 -070069 @Reference(cardinality = ReferenceCardinality.MANDATORY)
YuanyouZhangb5e05302015-07-21 20:14:35 +080070 protected OvsdbController controller;
71
Ray Milkeyd84f89b2018-08-17 14:54:17 -070072 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Michal Mach958adf62017-06-05 16:29:13 +020073 protected DeviceService deviceService;
74
Ray Milkeyd84f89b2018-08-17 14:54:17 -070075 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Michal Mach958adf62017-06-05 16:29:13 +020076 protected MastershipService mastershipService;
77
YuanyouZhangb5e05302015-07-21 20:14:35 +080078 private DeviceProviderService providerService;
79 private OvsdbNodeListener innerNodeListener = new InnerOvsdbNodeListener();
Michal Mach958adf62017-06-05 16:29:13 +020080 private InternalDeviceListener deviceListener = new InternalDeviceListener();
YuanyouZhangb5e05302015-07-21 20:14:35 +080081 protected static final String ISNOTNULL = "OvsdbNodeId is not null";
Michal Mach958adf62017-06-05 16:29:13 +020082 protected static final String SCHEME_NAME = "ovsdb";
YuanyouZhangb5e05302015-07-21 20:14:35 +080083 private static final String UNKNOWN = "unknown";
84
Michal Mach958adf62017-06-05 16:29:13 +020085 protected ExecutorService executor =
86 Executors.newFixedThreadPool(5, groupedThreads("onos/ovsdbdeviceprovider",
87 "device-installer-%d", log));
88
YuanyouZhangb5e05302015-07-21 20:14:35 +080089 @Activate
90 public void activate() {
91 providerService = providerRegistry.register(this);
92 controller.addNodeListener(innerNodeListener);
Michal Mach958adf62017-06-05 16:29:13 +020093 deviceService.addListener(deviceListener);
YuanyouZhangb5e05302015-07-21 20:14:35 +080094 log.info("Started");
95 }
96
97 @Deactivate
98 public void deactivate() {
Frank Wang14629822017-05-26 09:22:59 +080099 controller.removeNodeListener(innerNodeListener);
YuanyouZhangb5e05302015-07-21 20:14:35 +0800100 providerRegistry.unregister(this);
Michal Mach958adf62017-06-05 16:29:13 +0200101 deviceService.removeListener(deviceListener);
102 waitForTasksToEnd();
YuanyouZhangb5e05302015-07-21 20:14:35 +0800103 providerService = null;
104 log.info("Stopped");
105 }
106
107 public OvsdbDeviceProvider() {
108 super(new ProviderId("ovsdb", "org.onosproject.ovsdb.provider.device"));
109 }
110
111 @Override
112 public void triggerProbe(DeviceId deviceId) {
YuanyouZhangb5e05302015-07-21 20:14:35 +0800113 log.info("Triggering probe on device {}", deviceId);
jiangrui5f4d2e62015-11-16 12:52:35 +0800114 if (!isReachable(deviceId)) {
115 log.error("Failed to probe device {}", deviceId);
116 providerService.deviceDisconnected(deviceId);
jiangrui5f4d2e62015-11-16 12:52:35 +0800117 } else {
118 log.trace("Confirmed device {} connection", deviceId);
119 }
YuanyouZhangb5e05302015-07-21 20:14:35 +0800120 }
121
122 @Override
123 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
124 // TODO: This will be implemented later.
125 }
126
127 @Override
128 public boolean isReachable(DeviceId deviceId) {
jiangrui83563612015-11-16 11:59:47 +0800129 OvsdbClientService ovsdbClient = controller.getOvsdbClient(changeDeviceIdToNodeId(deviceId));
130 return !(ovsdbClient == null || !ovsdbClient.isConnected());
YuanyouZhangb5e05302015-07-21 20:14:35 +0800131 }
132
133 private class InnerOvsdbNodeListener implements OvsdbNodeListener {
134
135 @Override
136 public void nodeAdded(OvsdbNodeId nodeId) {
137 checkNotNull(nodeId, ISNOTNULL);
138 DeviceId deviceId = DeviceId.deviceId(nodeId.toString());
139 URI uri = URI.create(nodeId.toString());
140 ChassisId cid = new ChassisId();
141 String ipAddress = nodeId.getIpAddress();
142 SparseAnnotations annotations = DefaultAnnotations.builder()
143 .set("ipaddress", ipAddress).build();
144 DeviceDescription deviceDescription = new DefaultDeviceDescription(
145 uri,
146 Device.Type.CONTROLLER,
147 UNKNOWN, UNKNOWN,
148 UNKNOWN, UNKNOWN,
149 cid,
150 annotations);
151 providerService.deviceConnected(deviceId, deviceDescription);
152
153 }
154
155 @Override
156 public void nodeRemoved(OvsdbNodeId nodeId) {
157 checkNotNull(nodeId, ISNOTNULL);
158 DeviceId deviceId = DeviceId.deviceId(nodeId.toString());
159 providerService.deviceDisconnected(deviceId);
160
161 }
162 }
jiangrui83563612015-11-16 11:59:47 +0800163
164 private OvsdbNodeId changeDeviceIdToNodeId(DeviceId deviceId) {
165 String[] strings = deviceId.toString().split(":");
166 if (strings.length < 1) {
167 return null;
168 }
169 return new OvsdbNodeId(IpAddress.valueOf(strings[1]), 0);
170 }
Saurav Dasa2d37502016-03-25 17:50:40 -0700171
172 @Override
173 public void changePortState(DeviceId deviceId, PortNumber portNumber,
174 boolean enable) {
175 // TODO if required
176 }
Michal Mach958adf62017-06-05 16:29:13 +0200177
178 private void discoverPorts(DeviceId deviceId) {
179 Device device = deviceService.getDevice(deviceId);
180 if (device.is(DeviceDescriptionDiscovery.class)) {
181 DeviceDescriptionDiscovery deviceDescriptionDiscovery = device.as(DeviceDescriptionDiscovery.class);
182 providerService.updatePorts(deviceId, deviceDescriptionDiscovery.discoverPortDetails());
183 } else {
184 log.warn("Device " + deviceId + " does not support behaviour DeviceDescriptionDiscovery");
185 }
186 }
187
Thomas Vachuska5b38dc02018-05-10 15:24:40 -0700188 @Override
189 public void triggerDisconnect(DeviceId deviceId) {
190 log.debug("Forcing disconnect for device {}", deviceId);
191 OvsdbNodeId ovsdbNodeId = changeDeviceIdToNodeId(deviceId);
192 OvsdbClientService client = controller.getOvsdbClient(ovsdbNodeId);
193 if (client != null) {
194 client.disconnect();
195 }
196 }
197
Michal Mach958adf62017-06-05 16:29:13 +0200198 private class InternalDeviceListener implements DeviceListener {
199 @Override
200 public void event(DeviceEvent event) {
Thomas Vachuska5b38dc02018-05-10 15:24:40 -0700201 executor.execute(() -> discoverPorts(event.subject().id()));
Michal Mach958adf62017-06-05 16:29:13 +0200202 }
203
204 @Override
205 public boolean isRelevant(DeviceEvent event) {
206 DeviceId deviceId = event.subject().id();
Thomas Vachuska5b38dc02018-05-10 15:24:40 -0700207 return event.type() == DeviceEvent.Type.DEVICE_ADDED &&
208 isRelevant(deviceId) && mastershipService.isLocalMaster(deviceId);
Michal Mach958adf62017-06-05 16:29:13 +0200209 }
210
211 private boolean isRelevant(DeviceId deviceId) {
212 return deviceId.uri().getScheme().equals(SCHEME_NAME);
213 }
214 }
215
216 private void waitForTasksToEnd() {
217 executor.shutdown();
218 try {
219 executor.awaitTermination(5, TimeUnit.SECONDS);
220 } catch (InterruptedException e) {
221 log.error("Timeout while waiting for child threads to finish because: " + e.getMessage());
Ray Milkey5c7d4882018-02-05 14:50:39 -0800222 Thread.currentThread().interrupt();
Michal Mach958adf62017-06-05 16:29:13 +0200223 }
224 }
YuanyouZhangb5e05302015-07-21 20:14:35 +0800225}