blob: bc2bc8dd694ad58544bc4ba746d1a43fc2ef0c41 [file] [log] [blame]
Thomas Vachuska11b99fc2017-04-27 12:51:04 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Thomas Vachuska11b99fc2017-04-27 12:51:04 -07003 *
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.net.driver.impl;
17
18import com.google.common.collect.ImmutableSet;
19import com.google.common.collect.Maps;
20import com.google.common.collect.Sets;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070021import org.onosproject.net.driver.DriverRegistry;
22import org.osgi.service.component.annotations.Activate;
23import org.osgi.service.component.annotations.Component;
24import org.osgi.service.component.annotations.Deactivate;
25import org.osgi.service.component.annotations.Modified;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070026import org.osgi.service.component.annotations.Reference;
27import org.osgi.service.component.annotations.ReferenceCardinality;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070028import org.onosproject.cfg.ComponentConfigService;
Ray Milkeye56c34d2017-08-03 13:39:30 -070029import org.onosproject.component.ComponentService;
Thomas Vachuskae6a57412017-08-23 14:09:14 -070030import org.onosproject.event.EventDeliveryService;
31import org.onosproject.event.ListenerRegistry;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070032import org.onosproject.net.device.DeviceService;
33import org.onosproject.net.driver.Behaviour;
34import org.onosproject.net.driver.DefaultDriverProvider;
35import org.onosproject.net.driver.Driver;
36import org.onosproject.net.driver.DriverAdminService;
Thomas Vachuskae6a57412017-08-23 14:09:14 -070037import org.onosproject.net.driver.DriverEvent;
38import org.onosproject.net.driver.DriverListener;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070039import org.onosproject.net.driver.DriverProvider;
40import org.osgi.service.component.ComponentContext;
41import org.slf4j.Logger;
42import org.slf4j.LoggerFactory;
43
44import java.util.Dictionary;
45import java.util.Map;
46import java.util.Optional;
47import java.util.Properties;
48import java.util.Set;
49
50import static com.google.common.base.Strings.isNullOrEmpty;
51import static org.onlab.util.Tools.get;
52import static org.onlab.util.Tools.nullIsNotFound;
Thomas Vachuskae6a57412017-08-23 14:09:14 -070053import static org.onosproject.net.driver.DriverEvent.Type.DRIVER_ENHANCED;
54import static org.onosproject.net.driver.DriverEvent.Type.DRIVER_REDUCED;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070055import static org.onosproject.security.AppGuard.checkPermission;
56import static org.onosproject.security.AppPermission.Type.DRIVER_READ;
57
58
59/**
60 * Manages inventory of device drivers.
61 */
Ray Milkey89bbf812018-11-21 12:19:54 -080062@Component(
63 immediate = true,
64 service = {
65 DriverAdminService.class,
66 DriverRegistry.class
67 }
68)
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070069public class DriverRegistryManager extends DefaultDriverProvider implements DriverAdminService {
70
71 private static final String DRIVER_COMPONENT = "org.onosproject.net.driver.impl.DriverManager";
72
73 private final Logger log = LoggerFactory.getLogger(getClass());
74
75 private static final String FORMAT = "Required drivers: {}";
76 private static final String COMMA = ",";
77 private static final String NO_DRIVER = "Driver not found";
78 private static final String DEFAULT = "default";
79
Ray Milkeyd84f89b2018-08-17 14:54:17 -070080 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070081 protected DeviceService deviceService;
82
Ray Milkeyd84f89b2018-08-17 14:54:17 -070083 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070084 protected ComponentConfigService componentConfigService;
85
Ray Milkeyd84f89b2018-08-17 14:54:17 -070086 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070087 protected ComponentService componenService;
88
Ray Milkeyd84f89b2018-08-17 14:54:17 -070089 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskae6a57412017-08-23 14:09:14 -070090 protected EventDeliveryService eventDispatcher;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070091
92 private static final String DEFAULT_REQUIRED_DRIVERS = "default";
Ray Milkeyd84f89b2018-08-17 14:54:17 -070093 private static String requiredDrivers = DEFAULT_REQUIRED_DRIVERS;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070094 private Set<String> requiredDriverSet;
95
96 private Set<DriverProvider> providers = Sets.newConcurrentHashSet();
97 private Map<String, Driver> driverByKey = Maps.newConcurrentMap();
98 private Map<String, Class<? extends Behaviour>> classes = Maps.newConcurrentMap();
99
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700100 private ListenerRegistry<DriverEvent, DriverListener> listenerRegistry;
101
102
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700103 private boolean isStarted = false;
104
105 @Activate
106 protected void activate(ComponentContext context) {
107 componentConfigService.registerProperties(getClass());
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700108 listenerRegistry = new ListenerRegistry<>();
109 eventDispatcher.addSink(DriverEvent.class, listenerRegistry);
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700110 modified(context);
111 log.info("Started");
112 }
113
114 @Deactivate
115 protected void deactivate() {
116 componentConfigService.unregisterProperties(getClass(), false);
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700117 eventDispatcher.removeSink(DriverEvent.class);
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700118 providers.clear();
119 driverByKey.clear();
120 classes.clear();
121 log.info("Stopped");
122 }
123
124 @Modified
125 public void modified(ComponentContext context) {
126 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
127 if (context != null) {
128 requiredDrivers = get(properties, "requiredDrivers");
129 }
130 requiredDriverSet = isNullOrEmpty(requiredDrivers) ?
131 ImmutableSet.of() : ImmutableSet.copyOf(requiredDrivers.split(COMMA));
132 log.info(FORMAT, requiredDrivers);
133 checkRequiredDrivers();
134 }
135
136 @Override
137 public Set<DriverProvider> getProviders() {
138 return ImmutableSet.copyOf(providers);
139 }
140
141 @Override
142 public void registerProvider(DriverProvider provider) {
143 provider.getDrivers().forEach(driver -> {
144 Driver d = addDriver(driver);
145 driverByKey.put(key(driver.manufacturer(),
146 driver.hwVersion(),
147 driver.swVersion()), d);
148 d.behaviours().forEach(b -> {
149 Class<? extends Behaviour> implementation = d.implementation(b);
150 classes.put(b.getName(), b);
151 classes.put(implementation.getName(), implementation);
152 });
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700153 post(new DriverEvent(DRIVER_ENHANCED, driver));
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700154 });
155 providers.add(provider);
156 checkRequiredDrivers();
157 }
158
159 @Override
160 public void unregisterProvider(DriverProvider provider) {
161 provider.getDrivers().forEach(driver -> {
162 removeDriver(driver);
163 driverByKey.remove(key(driver.manufacturer(),
164 driver.hwVersion(),
165 driver.swVersion()));
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700166 post(new DriverEvent(DRIVER_REDUCED, driver));
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700167 });
168 providers.remove(provider);
169 checkRequiredDrivers();
170 }
171
172 // Checks for the minimum required drivers and when available, activate
173 // the driver manager components; deactivate otherwise.
174 private synchronized void checkRequiredDrivers() {
175 Set<String> driverSet = registeredDrivers();
176 boolean isReady = driverSet.containsAll(requiredDriverSet);
177 if (isReady && !isStarted) {
178 log.info("Starting driver subsystem");
179 componenService.activate(null, DRIVER_COMPONENT);
180 isStarted = true;
181 } else if (!isReady && isStarted) {
182 log.info("Stopping driver subsystem");
183 componenService.deactivate(null, DRIVER_COMPONENT);
184 isStarted = false;
185 }
186 }
187
188 private Set<String> registeredDrivers() {
189 ImmutableSet.Builder<String> builder = ImmutableSet.builder();
190 for (DriverProvider dp : providers) {
191 dp.getDrivers().stream().map(Driver::name).forEach(builder::add);
192 }
193 return builder.build();
194 }
195
196 @Override
197 public Class<? extends Behaviour> getBehaviourClass(String className) {
198 return classes.get(className);
199 }
200
201 @Override
202 public Set<Driver> getDrivers() {
203 checkPermission(DRIVER_READ);
204 ImmutableSet.Builder<Driver> builder = ImmutableSet.builder();
205 drivers.values().forEach(builder::add);
206 return builder.build();
207 }
208
209 @Override
210 public Driver getDriver(String mfr, String hw, String sw) {
211 checkPermission(DRIVER_READ);
212
213 // First attempt a literal search.
214 Driver driver = driverByKey.get(key(mfr, hw, sw));
215 if (driver != null) {
216 return driver;
217 }
218
219 // Otherwise, sweep through the key space and attempt to match using
220 // regular expression matching.
221 Optional<Driver> optional = driverByKey.values().stream()
222 .filter(d -> matches(d, mfr, hw, sw)).findFirst();
223
224 // If no matching driver is found, return default.
225 return optional.orElse(drivers.get(DEFAULT));
226 }
227
228 @Override
229 public Driver getDriver(String driverName) {
230 checkPermission(DRIVER_READ);
231 return nullIsNotFound(drivers.get(driverName), NO_DRIVER);
232 }
233
234 // Matches the given driver using ERE matching against the given criteria.
235 private boolean matches(Driver d, String mfr, String hw, String sw) {
236 // TODO: consider pre-compiling the expressions in the future
237 return mfr.matches(d.manufacturer()) &&
238 hw.matches(d.hwVersion()) &&
239 sw.matches(d.swVersion());
240 }
241
242 // Produces a composite driver key using the specified components.
243 static String key(String mfr, String hw, String sw) {
244 return String.format("%s-%s-%s", mfr, hw, sw);
245 }
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700246
247 @Override
248 public void addListener(DriverListener listener) {
249 listenerRegistry.addListener(listener);
250 }
251
252 @Override
253 public void removeListener(DriverListener listener) {
254 listenerRegistry.removeListener(listener);
255 }
256
257 // Safely posts the specified event to the local event dispatcher.
258 private void post(DriverEvent event) {
259 if (eventDispatcher != null) {
260 eventDispatcher.post(event);
261 }
262 }
263
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700264}