blob: fbb21ec213bf1e34b0c4ba1be5adf80ead79e9cb [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;
21import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Modified;
25import org.apache.felix.scr.annotations.Property;
26import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
28import org.apache.felix.scr.annotations.Service;
29import 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;
42import 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 */
63@Service
64@Component(immediate = true, enabled = true)
65public 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
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected DeviceService deviceService;
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected ComponentConfigService componentConfigService;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected ComponentService componenService;
84
Thomas Vachuskae6a57412017-08-23 14:09:14 -070085 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected EventDeliveryService eventDispatcher;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070087
88 private static final String DEFAULT_REQUIRED_DRIVERS = "default";
89 @Property(name = "requiredDrivers", value = DEFAULT_REQUIRED_DRIVERS,
90 label = "Comma-separated list of drivers that must be registered before starting driver subsystem")
91 private String requiredDrivers = DEFAULT_REQUIRED_DRIVERS;
92 private Set<String> requiredDriverSet;
93
94 private Set<DriverProvider> providers = Sets.newConcurrentHashSet();
95 private Map<String, Driver> driverByKey = Maps.newConcurrentMap();
96 private Map<String, Class<? extends Behaviour>> classes = Maps.newConcurrentMap();
97
Thomas Vachuskae6a57412017-08-23 14:09:14 -070098 private ListenerRegistry<DriverEvent, DriverListener> listenerRegistry;
99
100
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700101 private boolean isStarted = false;
102
103 @Activate
104 protected void activate(ComponentContext context) {
105 componentConfigService.registerProperties(getClass());
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700106 listenerRegistry = new ListenerRegistry<>();
107 eventDispatcher.addSink(DriverEvent.class, listenerRegistry);
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700108 modified(context);
109 log.info("Started");
110 }
111
112 @Deactivate
113 protected void deactivate() {
114 componentConfigService.unregisterProperties(getClass(), false);
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700115 eventDispatcher.removeSink(DriverEvent.class);
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700116 providers.clear();
117 driverByKey.clear();
118 classes.clear();
119 log.info("Stopped");
120 }
121
122 @Modified
123 public void modified(ComponentContext context) {
124 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
125 if (context != null) {
126 requiredDrivers = get(properties, "requiredDrivers");
127 }
128 requiredDriverSet = isNullOrEmpty(requiredDrivers) ?
129 ImmutableSet.of() : ImmutableSet.copyOf(requiredDrivers.split(COMMA));
130 log.info(FORMAT, requiredDrivers);
131 checkRequiredDrivers();
132 }
133
134 @Override
135 public Set<DriverProvider> getProviders() {
136 return ImmutableSet.copyOf(providers);
137 }
138
139 @Override
140 public void registerProvider(DriverProvider provider) {
141 provider.getDrivers().forEach(driver -> {
142 Driver d = addDriver(driver);
143 driverByKey.put(key(driver.manufacturer(),
144 driver.hwVersion(),
145 driver.swVersion()), d);
146 d.behaviours().forEach(b -> {
147 Class<? extends Behaviour> implementation = d.implementation(b);
148 classes.put(b.getName(), b);
149 classes.put(implementation.getName(), implementation);
150 });
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700151 post(new DriverEvent(DRIVER_ENHANCED, driver));
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700152 });
153 providers.add(provider);
154 checkRequiredDrivers();
155 }
156
157 @Override
158 public void unregisterProvider(DriverProvider provider) {
159 provider.getDrivers().forEach(driver -> {
160 removeDriver(driver);
161 driverByKey.remove(key(driver.manufacturer(),
162 driver.hwVersion(),
163 driver.swVersion()));
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700164 post(new DriverEvent(DRIVER_REDUCED, driver));
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700165 });
166 providers.remove(provider);
167 checkRequiredDrivers();
168 }
169
170 // Checks for the minimum required drivers and when available, activate
171 // the driver manager components; deactivate otherwise.
172 private synchronized void checkRequiredDrivers() {
173 Set<String> driverSet = registeredDrivers();
174 boolean isReady = driverSet.containsAll(requiredDriverSet);
175 if (isReady && !isStarted) {
176 log.info("Starting driver subsystem");
177 componenService.activate(null, DRIVER_COMPONENT);
178 isStarted = true;
179 } else if (!isReady && isStarted) {
180 log.info("Stopping driver subsystem");
181 componenService.deactivate(null, DRIVER_COMPONENT);
182 isStarted = false;
183 }
184 }
185
186 private Set<String> registeredDrivers() {
187 ImmutableSet.Builder<String> builder = ImmutableSet.builder();
188 for (DriverProvider dp : providers) {
189 dp.getDrivers().stream().map(Driver::name).forEach(builder::add);
190 }
191 return builder.build();
192 }
193
194 @Override
195 public Class<? extends Behaviour> getBehaviourClass(String className) {
196 return classes.get(className);
197 }
198
199 @Override
200 public Set<Driver> getDrivers() {
201 checkPermission(DRIVER_READ);
202 ImmutableSet.Builder<Driver> builder = ImmutableSet.builder();
203 drivers.values().forEach(builder::add);
204 return builder.build();
205 }
206
207 @Override
208 public Driver getDriver(String mfr, String hw, String sw) {
209 checkPermission(DRIVER_READ);
210
211 // First attempt a literal search.
212 Driver driver = driverByKey.get(key(mfr, hw, sw));
213 if (driver != null) {
214 return driver;
215 }
216
217 // Otherwise, sweep through the key space and attempt to match using
218 // regular expression matching.
219 Optional<Driver> optional = driverByKey.values().stream()
220 .filter(d -> matches(d, mfr, hw, sw)).findFirst();
221
222 // If no matching driver is found, return default.
223 return optional.orElse(drivers.get(DEFAULT));
224 }
225
226 @Override
227 public Driver getDriver(String driverName) {
228 checkPermission(DRIVER_READ);
229 return nullIsNotFound(drivers.get(driverName), NO_DRIVER);
230 }
231
232 // Matches the given driver using ERE matching against the given criteria.
233 private boolean matches(Driver d, String mfr, String hw, String sw) {
234 // TODO: consider pre-compiling the expressions in the future
235 return mfr.matches(d.manufacturer()) &&
236 hw.matches(d.hwVersion()) &&
237 sw.matches(d.swVersion());
238 }
239
240 // Produces a composite driver key using the specified components.
241 static String key(String mfr, String hw, String sw) {
242 return String.format("%s-%s-%s", mfr, hw, sw);
243 }
Thomas Vachuskae6a57412017-08-23 14:09:14 -0700244
245 @Override
246 public void addListener(DriverListener listener) {
247 listenerRegistry.addListener(listener);
248 }
249
250 @Override
251 public void removeListener(DriverListener listener) {
252 listenerRegistry.removeListener(listener);
253 }
254
255 // Safely posts the specified event to the local event dispatcher.
256 private void post(DriverEvent event) {
257 if (eventDispatcher != null) {
258 eventDispatcher.post(event);
259 }
260 }
261
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700262}