blob: b4b7b8e39f43cc326f7719c040c6d58d85a56486 [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;
26import org.osgi.service.component.annotations.ComponentPropertyType;
27import org.osgi.service.component.annotations.Reference;
28import org.osgi.service.component.annotations.ReferenceCardinality;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070029import org.onosproject.cfg.ComponentConfigService;
Ray Milkeye56c34d2017-08-03 13:39:30 -070030import org.onosproject.component.ComponentService;
Thomas Vachuskae6a57412017-08-23 14:09:14 -070031import org.onosproject.event.EventDeliveryService;
32import org.onosproject.event.ListenerRegistry;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070033import org.onosproject.net.device.DeviceService;
34import org.onosproject.net.driver.Behaviour;
35import org.onosproject.net.driver.DefaultDriverProvider;
36import org.onosproject.net.driver.Driver;
37import org.onosproject.net.driver.DriverAdminService;
Thomas Vachuskae6a57412017-08-23 14:09:14 -070038import org.onosproject.net.driver.DriverEvent;
39import org.onosproject.net.driver.DriverListener;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070040import org.onosproject.net.driver.DriverProvider;
41import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070042//import org.osgi.service.metatype.annotations.AttributeDefinition;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070043import org.slf4j.Logger;
44import org.slf4j.LoggerFactory;
45
46import java.util.Dictionary;
47import java.util.Map;
48import java.util.Optional;
49import java.util.Properties;
50import java.util.Set;
51
52import static com.google.common.base.Strings.isNullOrEmpty;
53import static org.onlab.util.Tools.get;
54import static org.onlab.util.Tools.nullIsNotFound;
Thomas Vachuskae6a57412017-08-23 14:09:14 -070055import static org.onosproject.net.driver.DriverEvent.Type.DRIVER_ENHANCED;
56import static org.onosproject.net.driver.DriverEvent.Type.DRIVER_REDUCED;
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 Milkeyd84f89b2018-08-17 14:54:17 -070064@Component(immediate = true, enabled = true, service = {DriverAdminService.class, DriverRegistry.class})
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070065public class DriverRegistryManager extends DefaultDriverProvider implements DriverAdminService {
66
67 private static final String DRIVER_COMPONENT = "org.onosproject.net.driver.impl.DriverManager";
68
69 private final Logger log = LoggerFactory.getLogger(getClass());
70
71 private static final String FORMAT = "Required drivers: {}";
72 private static final String COMMA = ",";
73 private static final String NO_DRIVER = "Driver not found";
74 private static final String DEFAULT = "default";
75
Ray Milkeyd84f89b2018-08-17 14:54:17 -070076 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070077 protected DeviceService deviceService;
78
Ray Milkeyd84f89b2018-08-17 14:54:17 -070079 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070080 protected ComponentConfigService componentConfigService;
81
Ray Milkeyd84f89b2018-08-17 14:54:17 -070082 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070083 protected ComponentService componenService;
84
Ray Milkeyd84f89b2018-08-17 14:54:17 -070085 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskae6a57412017-08-23 14:09:14 -070086 protected EventDeliveryService eventDispatcher;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070087
88 private static final String DEFAULT_REQUIRED_DRIVERS = "default";
Ray Milkeyd84f89b2018-08-17 14:54:17 -070089 private static String requiredDrivers = DEFAULT_REQUIRED_DRIVERS;
90 //@AttributeDefinition(name = "requiredDrivers",
91 // defaultValue = DEFAULT_REQUIRED_DRIVERS + "AAA",
92 // description = "Comma-separated list of drivers that must be registered before starting driver subsystem")
93 private String requiredDrivers() {
94 return requiredDrivers;
95 }
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070096 private Set<String> requiredDriverSet;
97
98 private Set<DriverProvider> providers = Sets.newConcurrentHashSet();
99 private Map<String, Driver> driverByKey = Maps.newConcurrentMap();
100 private Map<String, Class<? extends Behaviour>> classes = Maps.newConcurrentMap();
101
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700102 private ListenerRegistry<DriverEvent, DriverListener> listenerRegistry;
103
104
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700105 private boolean isStarted = false;
106
107 @Activate
108 protected void activate(ComponentContext context) {
109 componentConfigService.registerProperties(getClass());
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700110 listenerRegistry = new ListenerRegistry<>();
111 eventDispatcher.addSink(DriverEvent.class, listenerRegistry);
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700112 modified(context);
113 log.info("Started");
114 }
115
116 @Deactivate
117 protected void deactivate() {
118 componentConfigService.unregisterProperties(getClass(), false);
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700119 eventDispatcher.removeSink(DriverEvent.class);
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700120 providers.clear();
121 driverByKey.clear();
122 classes.clear();
123 log.info("Stopped");
124 }
125
126 @Modified
127 public void modified(ComponentContext context) {
128 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
129 if (context != null) {
130 requiredDrivers = get(properties, "requiredDrivers");
131 }
132 requiredDriverSet = isNullOrEmpty(requiredDrivers) ?
133 ImmutableSet.of() : ImmutableSet.copyOf(requiredDrivers.split(COMMA));
134 log.info(FORMAT, requiredDrivers);
135 checkRequiredDrivers();
136 }
137
138 @Override
139 public Set<DriverProvider> getProviders() {
140 return ImmutableSet.copyOf(providers);
141 }
142
143 @Override
144 public void registerProvider(DriverProvider provider) {
145 provider.getDrivers().forEach(driver -> {
146 Driver d = addDriver(driver);
147 driverByKey.put(key(driver.manufacturer(),
148 driver.hwVersion(),
149 driver.swVersion()), d);
150 d.behaviours().forEach(b -> {
151 Class<? extends Behaviour> implementation = d.implementation(b);
152 classes.put(b.getName(), b);
153 classes.put(implementation.getName(), implementation);
154 });
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700155 post(new DriverEvent(DRIVER_ENHANCED, driver));
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700156 });
157 providers.add(provider);
158 checkRequiredDrivers();
159 }
160
161 @Override
162 public void unregisterProvider(DriverProvider provider) {
163 provider.getDrivers().forEach(driver -> {
164 removeDriver(driver);
165 driverByKey.remove(key(driver.manufacturer(),
166 driver.hwVersion(),
167 driver.swVersion()));
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700168 post(new DriverEvent(DRIVER_REDUCED, driver));
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700169 });
170 providers.remove(provider);
171 checkRequiredDrivers();
172 }
173
174 // Checks for the minimum required drivers and when available, activate
175 // the driver manager components; deactivate otherwise.
176 private synchronized void checkRequiredDrivers() {
177 Set<String> driverSet = registeredDrivers();
178 boolean isReady = driverSet.containsAll(requiredDriverSet);
179 if (isReady && !isStarted) {
180 log.info("Starting driver subsystem");
181 componenService.activate(null, DRIVER_COMPONENT);
182 isStarted = true;
183 } else if (!isReady && isStarted) {
184 log.info("Stopping driver subsystem");
185 componenService.deactivate(null, DRIVER_COMPONENT);
186 isStarted = false;
187 }
188 }
189
190 private Set<String> registeredDrivers() {
191 ImmutableSet.Builder<String> builder = ImmutableSet.builder();
192 for (DriverProvider dp : providers) {
193 dp.getDrivers().stream().map(Driver::name).forEach(builder::add);
194 }
195 return builder.build();
196 }
197
198 @Override
199 public Class<? extends Behaviour> getBehaviourClass(String className) {
200 return classes.get(className);
201 }
202
203 @Override
204 public Set<Driver> getDrivers() {
205 checkPermission(DRIVER_READ);
206 ImmutableSet.Builder<Driver> builder = ImmutableSet.builder();
207 drivers.values().forEach(builder::add);
208 return builder.build();
209 }
210
211 @Override
212 public Driver getDriver(String mfr, String hw, String sw) {
213 checkPermission(DRIVER_READ);
214
215 // First attempt a literal search.
216 Driver driver = driverByKey.get(key(mfr, hw, sw));
217 if (driver != null) {
218 return driver;
219 }
220
221 // Otherwise, sweep through the key space and attempt to match using
222 // regular expression matching.
223 Optional<Driver> optional = driverByKey.values().stream()
224 .filter(d -> matches(d, mfr, hw, sw)).findFirst();
225
226 // If no matching driver is found, return default.
227 return optional.orElse(drivers.get(DEFAULT));
228 }
229
230 @Override
231 public Driver getDriver(String driverName) {
232 checkPermission(DRIVER_READ);
233 return nullIsNotFound(drivers.get(driverName), NO_DRIVER);
234 }
235
236 // Matches the given driver using ERE matching against the given criteria.
237 private boolean matches(Driver d, String mfr, String hw, String sw) {
238 // TODO: consider pre-compiling the expressions in the future
239 return mfr.matches(d.manufacturer()) &&
240 hw.matches(d.hwVersion()) &&
241 sw.matches(d.swVersion());
242 }
243
244 // Produces a composite driver key using the specified components.
245 static String key(String mfr, String hw, String sw) {
246 return String.format("%s-%s-%s", mfr, hw, sw);
247 }
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700248
249 @Override
250 public void addListener(DriverListener listener) {
251 listenerRegistry.addListener(listener);
252 }
253
254 @Override
255 public void removeListener(DriverListener listener) {
256 listenerRegistry.removeListener(listener);
257 }
258
259 // Safely posts the specified event to the local event dispatcher.
260 private void post(DriverEvent event) {
261 if (eventDispatcher != null) {
262 eventDispatcher.post(event);
263 }
264 }
265
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700266}