blob: 546f40a2fe3ea1a072c60b80924e8d0e4bb023b4 [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
80 private static final String FORMAT = "Required drivers: {}";
81 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);
182 if (isReady && !isStarted) {
183 log.info("Starting driver subsystem");
Ray Milkey8a064032019-04-04 14:38:48 -0700184 componentService.activate(null, DRIVER_COMPONENT);
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700185 isStarted = true;
186 } else if (!isReady && isStarted) {
187 log.info("Stopping driver subsystem");
Ray Milkey8a064032019-04-04 14:38:48 -0700188 componentService.deactivate(null, DRIVER_COMPONENT);
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700189 isStarted = false;
190 }
191 }
192
193 private Set<String> registeredDrivers() {
194 ImmutableSet.Builder<String> builder = ImmutableSet.builder();
195 for (DriverProvider dp : providers) {
196 dp.getDrivers().stream().map(Driver::name).forEach(builder::add);
197 }
198 return builder.build();
199 }
200
201 @Override
202 public Class<? extends Behaviour> getBehaviourClass(String className) {
203 return classes.get(className);
204 }
205
206 @Override
207 public Set<Driver> getDrivers() {
208 checkPermission(DRIVER_READ);
209 ImmutableSet.Builder<Driver> builder = ImmutableSet.builder();
210 drivers.values().forEach(builder::add);
211 return builder.build();
212 }
213
214 @Override
215 public Driver getDriver(String mfr, String hw, String sw) {
216 checkPermission(DRIVER_READ);
217
218 // First attempt a literal search.
219 Driver driver = driverByKey.get(key(mfr, hw, sw));
220 if (driver != null) {
221 return driver;
222 }
223
224 // Otherwise, sweep through the key space and attempt to match using
225 // regular expression matching.
226 Optional<Driver> optional = driverByKey.values().stream()
227 .filter(d -> matches(d, mfr, hw, sw)).findFirst();
228
229 // If no matching driver is found, return default.
230 return optional.orElse(drivers.get(DEFAULT));
231 }
232
233 @Override
234 public Driver getDriver(String driverName) {
235 checkPermission(DRIVER_READ);
236 return nullIsNotFound(drivers.get(driverName), NO_DRIVER);
237 }
238
239 // Matches the given driver using ERE matching against the given criteria.
240 private boolean matches(Driver d, String mfr, String hw, String sw) {
241 // TODO: consider pre-compiling the expressions in the future
242 return mfr.matches(d.manufacturer()) &&
243 hw.matches(d.hwVersion()) &&
244 sw.matches(d.swVersion());
245 }
246
247 // Produces a composite driver key using the specified components.
248 static String key(String mfr, String hw, String sw) {
249 return String.format("%s-%s-%s", mfr, hw, sw);
250 }
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700251
252 @Override
253 public void addListener(DriverListener listener) {
254 listenerRegistry.addListener(listener);
255 }
256
257 @Override
258 public void removeListener(DriverListener listener) {
259 listenerRegistry.removeListener(listener);
260 }
261
262 // Safely posts the specified event to the local event dispatcher.
263 private void post(DriverEvent event) {
264 if (eventDispatcher != null) {
265 eventDispatcher.post(event);
266 }
267 }
268
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700269}