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