blob: 834b88cd37bf6a20081c378d016f5ab3a71fd917 [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;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070021import org.onosproject.cfg.ComponentConfigService;
Ray Milkeye56c34d2017-08-03 13:39:30 -070022import org.onosproject.component.ComponentService;
Thomas Vachuskae6a57412017-08-23 14:09:14 -070023import org.onosproject.event.EventDeliveryService;
24import org.onosproject.event.ListenerRegistry;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070025import org.onosproject.net.device.DeviceService;
26import org.onosproject.net.driver.Behaviour;
27import org.onosproject.net.driver.DefaultDriverProvider;
28import org.onosproject.net.driver.Driver;
29import org.onosproject.net.driver.DriverAdminService;
Thomas Vachuskae6a57412017-08-23 14:09:14 -070030import org.onosproject.net.driver.DriverEvent;
31import org.onosproject.net.driver.DriverListener;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070032import org.onosproject.net.driver.DriverProvider;
Ray Milkey1f0764a2019-03-01 08:40:37 -080033import org.onosproject.net.driver.DriverRegistry;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070034import org.osgi.service.component.ComponentContext;
Ray Milkey1f0764a2019-03-01 08:40:37 -080035import org.osgi.service.component.annotations.Activate;
36import org.osgi.service.component.annotations.Component;
37import org.osgi.service.component.annotations.Deactivate;
38import org.osgi.service.component.annotations.Modified;
39import org.osgi.service.component.annotations.Reference;
40import org.osgi.service.component.annotations.ReferenceCardinality;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070041import 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;
Ray Milkey1f0764a2019-03-01 08:40:37 -080055import static org.onosproject.net.driver.impl.OsgiPropertyConstants.REQUIRED_DRIVERS;
56import static org.onosproject.net.driver.impl.OsgiPropertyConstants.REQUIRED_DRIVERS_DEFAULT;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070057import static org.onosproject.security.AppGuard.checkPermission;
58import static org.onosproject.security.AppPermission.Type.DRIVER_READ;
59
60
61/**
62 * Manages inventory of device drivers.
63 */
Ray Milkey89bbf812018-11-21 12:19:54 -080064@Component(
65 immediate = true,
66 service = {
67 DriverAdminService.class,
68 DriverRegistry.class
Ray Milkey1f0764a2019-03-01 08:40:37 -080069 },
70 property = {
71 REQUIRED_DRIVERS + "=" + REQUIRED_DRIVERS_DEFAULT,
72 })
73
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070074public class DriverRegistryManager extends DefaultDriverProvider implements DriverAdminService {
75
76 private static final String DRIVER_COMPONENT = "org.onosproject.net.driver.impl.DriverManager";
77
78 private final Logger log = LoggerFactory.getLogger(getClass());
79
Andrea Campanellaffae6e82021-03-26 10:34:30 +010080 private static final String FORMAT = "Modified, Required drivers: {}";
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070081 private static final String COMMA = ",";
82 private static final String NO_DRIVER = "Driver not found";
83 private static final String DEFAULT = "default";
84
Ray Milkeyd84f89b2018-08-17 14:54:17 -070085 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070086 protected DeviceService deviceService;
87
Ray Milkeyd84f89b2018-08-17 14:54:17 -070088 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070089 protected ComponentConfigService componentConfigService;
90
Ray Milkeyd84f89b2018-08-17 14:54:17 -070091 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkey8a064032019-04-04 14:38:48 -070092 protected ComponentService componentService;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070093
Ray Milkeyd84f89b2018-08-17 14:54:17 -070094 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskae6a57412017-08-23 14:09:14 -070095 protected EventDeliveryService eventDispatcher;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070096
Ray Milkey1f0764a2019-03-01 08:40:37 -080097 /** Comma-separated list of drivers that must be registered before starting driver subsystem. */
98 private static String requiredDrivers = REQUIRED_DRIVERS_DEFAULT;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070099 private Set<String> requiredDriverSet;
100
101 private Set<DriverProvider> providers = Sets.newConcurrentHashSet();
102 private Map<String, Driver> driverByKey = Maps.newConcurrentMap();
103 private Map<String, Class<? extends Behaviour>> classes = Maps.newConcurrentMap();
104
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700105 private ListenerRegistry<DriverEvent, DriverListener> listenerRegistry;
106
107
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700108 private boolean isStarted = false;
109
110 @Activate
111 protected void activate(ComponentContext context) {
112 componentConfigService.registerProperties(getClass());
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700113 listenerRegistry = new ListenerRegistry<>();
114 eventDispatcher.addSink(DriverEvent.class, listenerRegistry);
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700115 modified(context);
116 log.info("Started");
117 }
118
119 @Deactivate
120 protected void deactivate() {
121 componentConfigService.unregisterProperties(getClass(), false);
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700122 eventDispatcher.removeSink(DriverEvent.class);
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700123 providers.clear();
124 driverByKey.clear();
125 classes.clear();
126 log.info("Stopped");
127 }
128
129 @Modified
130 public void modified(ComponentContext context) {
131 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
132 if (context != null) {
Ray Milkey1f0764a2019-03-01 08:40:37 -0800133 requiredDrivers = get(properties, REQUIRED_DRIVERS);
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700134 }
135 requiredDriverSet = isNullOrEmpty(requiredDrivers) ?
136 ImmutableSet.of() : ImmutableSet.copyOf(requiredDrivers.split(COMMA));
137 log.info(FORMAT, requiredDrivers);
138 checkRequiredDrivers();
139 }
140
141 @Override
142 public Set<DriverProvider> getProviders() {
143 return ImmutableSet.copyOf(providers);
144 }
145
146 @Override
147 public void registerProvider(DriverProvider provider) {
148 provider.getDrivers().forEach(driver -> {
149 Driver d = addDriver(driver);
150 driverByKey.put(key(driver.manufacturer(),
151 driver.hwVersion(),
152 driver.swVersion()), d);
153 d.behaviours().forEach(b -> {
154 Class<? extends Behaviour> implementation = d.implementation(b);
155 classes.put(b.getName(), b);
156 classes.put(implementation.getName(), implementation);
157 });
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700158 post(new DriverEvent(DRIVER_ENHANCED, driver));
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700159 });
160 providers.add(provider);
161 checkRequiredDrivers();
162 }
163
164 @Override
165 public void unregisterProvider(DriverProvider provider) {
166 provider.getDrivers().forEach(driver -> {
167 removeDriver(driver);
168 driverByKey.remove(key(driver.manufacturer(),
169 driver.hwVersion(),
170 driver.swVersion()));
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700171 post(new DriverEvent(DRIVER_REDUCED, driver));
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700172 });
173 providers.remove(provider);
174 checkRequiredDrivers();
175 }
176
177 // Checks for the minimum required drivers and when available, activate
178 // the driver manager components; deactivate otherwise.
179 private synchronized void checkRequiredDrivers() {
180 Set<String> driverSet = registeredDrivers();
181 boolean isReady = driverSet.containsAll(requiredDriverSet);
Andrea Campanellaffae6e82021-03-26 10:34:30 +0100182 log.debug("RequiredDriverSet {}, isReady {}, isStarted {}",
183 requiredDriverSet, isReady, isStarted);
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700184 if (isReady && !isStarted) {
185 log.info("Starting driver subsystem");
Ray Milkey8a064032019-04-04 14:38:48 -0700186 componentService.activate(null, DRIVER_COMPONENT);
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700187 isStarted = true;
188 } else if (!isReady && isStarted) {
189 log.info("Stopping driver subsystem");
Ray Milkey8a064032019-04-04 14:38:48 -0700190 componentService.deactivate(null, DRIVER_COMPONENT);
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700191 isStarted = false;
192 }
193 }
194
195 private Set<String> registeredDrivers() {
196 ImmutableSet.Builder<String> builder = ImmutableSet.builder();
197 for (DriverProvider dp : providers) {
198 dp.getDrivers().stream().map(Driver::name).forEach(builder::add);
199 }
200 return builder.build();
201 }
202
203 @Override
204 public Class<? extends Behaviour> getBehaviourClass(String className) {
205 return classes.get(className);
206 }
207
208 @Override
209 public Set<Driver> getDrivers() {
210 checkPermission(DRIVER_READ);
211 ImmutableSet.Builder<Driver> builder = ImmutableSet.builder();
212 drivers.values().forEach(builder::add);
213 return builder.build();
214 }
215
216 @Override
217 public Driver getDriver(String mfr, String hw, String sw) {
218 checkPermission(DRIVER_READ);
219
220 // First attempt a literal search.
221 Driver driver = driverByKey.get(key(mfr, hw, sw));
222 if (driver != null) {
223 return driver;
224 }
225
226 // Otherwise, sweep through the key space and attempt to match using
227 // regular expression matching.
228 Optional<Driver> optional = driverByKey.values().stream()
229 .filter(d -> matches(d, mfr, hw, sw)).findFirst();
230
231 // If no matching driver is found, return default.
232 return optional.orElse(drivers.get(DEFAULT));
233 }
234
235 @Override
236 public Driver getDriver(String driverName) {
237 checkPermission(DRIVER_READ);
238 return nullIsNotFound(drivers.get(driverName), NO_DRIVER);
239 }
240
241 // Matches the given driver using ERE matching against the given criteria.
242 private boolean matches(Driver d, String mfr, String hw, String sw) {
243 // TODO: consider pre-compiling the expressions in the future
244 return mfr.matches(d.manufacturer()) &&
245 hw.matches(d.hwVersion()) &&
246 sw.matches(d.swVersion());
247 }
248
249 // Produces a composite driver key using the specified components.
250 static String key(String mfr, String hw, String sw) {
251 return String.format("%s-%s-%s", mfr, hw, sw);
252 }
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700253
254 @Override
255 public void addListener(DriverListener listener) {
256 listenerRegistry.addListener(listener);
257 }
258
259 @Override
260 public void removeListener(DriverListener listener) {
261 listenerRegistry.removeListener(listener);
262 }
263
264 // Safely posts the specified event to the local event dispatcher.
265 private void post(DriverEvent event) {
266 if (eventDispatcher != null) {
267 eventDispatcher.post(event);
268 }
269 }
270
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700271}