blob: 1a54b45e7a8831c549fb42e4f80b1197d385da15 [file] [log] [blame]
Thomas Vachuska11b99fc2017-04-27 12:51:04 -07001/*
2 * Copyright 2017-present Open Networking Laboratory
3 *
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 Vachuska11b99fc2017-04-27 12:51:04 -070031import org.onosproject.net.device.DeviceService;
32import org.onosproject.net.driver.Behaviour;
33import org.onosproject.net.driver.DefaultDriverProvider;
34import org.onosproject.net.driver.Driver;
35import org.onosproject.net.driver.DriverAdminService;
36import org.onosproject.net.driver.DriverProvider;
37import org.osgi.service.component.ComponentContext;
38import org.slf4j.Logger;
39import org.slf4j.LoggerFactory;
40
41import java.util.Dictionary;
42import java.util.Map;
43import java.util.Optional;
44import java.util.Properties;
45import java.util.Set;
46
47import static com.google.common.base.Strings.isNullOrEmpty;
48import static org.onlab.util.Tools.get;
49import static org.onlab.util.Tools.nullIsNotFound;
50import static org.onosproject.security.AppGuard.checkPermission;
51import static org.onosproject.security.AppPermission.Type.DRIVER_READ;
52
53
54/**
55 * Manages inventory of device drivers.
56 */
57@Service
58@Component(immediate = true, enabled = true)
59public class DriverRegistryManager extends DefaultDriverProvider implements DriverAdminService {
60
61 private static final String DRIVER_COMPONENT = "org.onosproject.net.driver.impl.DriverManager";
62
63 private final Logger log = LoggerFactory.getLogger(getClass());
64
65 private static final String FORMAT = "Required drivers: {}";
66 private static final String COMMA = ",";
67 private static final String NO_DRIVER = "Driver not found";
68 private static final String DEFAULT = "default";
69
70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected DeviceService deviceService;
72
73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected ComponentConfigService componentConfigService;
75
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected ComponentService componenService;
78
79
80 private static final String DEFAULT_REQUIRED_DRIVERS = "default";
81 @Property(name = "requiredDrivers", value = DEFAULT_REQUIRED_DRIVERS,
82 label = "Comma-separated list of drivers that must be registered before starting driver subsystem")
83 private String requiredDrivers = DEFAULT_REQUIRED_DRIVERS;
84 private Set<String> requiredDriverSet;
85
86 private Set<DriverProvider> providers = Sets.newConcurrentHashSet();
87 private Map<String, Driver> driverByKey = Maps.newConcurrentMap();
88 private Map<String, Class<? extends Behaviour>> classes = Maps.newConcurrentMap();
89
90 private boolean isStarted = false;
91
92 @Activate
93 protected void activate(ComponentContext context) {
94 componentConfigService.registerProperties(getClass());
95 modified(context);
96 log.info("Started");
97 }
98
99 @Deactivate
100 protected void deactivate() {
101 componentConfigService.unregisterProperties(getClass(), false);
102 providers.clear();
103 driverByKey.clear();
104 classes.clear();
105 log.info("Stopped");
106 }
107
108 @Modified
109 public void modified(ComponentContext context) {
110 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
111 if (context != null) {
112 requiredDrivers = get(properties, "requiredDrivers");
113 }
114 requiredDriverSet = isNullOrEmpty(requiredDrivers) ?
115 ImmutableSet.of() : ImmutableSet.copyOf(requiredDrivers.split(COMMA));
116 log.info(FORMAT, requiredDrivers);
117 checkRequiredDrivers();
118 }
119
120 @Override
121 public Set<DriverProvider> getProviders() {
122 return ImmutableSet.copyOf(providers);
123 }
124
125 @Override
126 public void registerProvider(DriverProvider provider) {
127 provider.getDrivers().forEach(driver -> {
128 Driver d = addDriver(driver);
129 driverByKey.put(key(driver.manufacturer(),
130 driver.hwVersion(),
131 driver.swVersion()), d);
132 d.behaviours().forEach(b -> {
133 Class<? extends Behaviour> implementation = d.implementation(b);
134 classes.put(b.getName(), b);
135 classes.put(implementation.getName(), implementation);
136 });
137 });
138 providers.add(provider);
139 checkRequiredDrivers();
140 }
141
142 @Override
143 public void unregisterProvider(DriverProvider provider) {
144 provider.getDrivers().forEach(driver -> {
145 removeDriver(driver);
146 driverByKey.remove(key(driver.manufacturer(),
147 driver.hwVersion(),
148 driver.swVersion()));
149 });
150 providers.remove(provider);
151 checkRequiredDrivers();
152 }
153
154 // Checks for the minimum required drivers and when available, activate
155 // the driver manager components; deactivate otherwise.
156 private synchronized void checkRequiredDrivers() {
157 Set<String> driverSet = registeredDrivers();
158 boolean isReady = driverSet.containsAll(requiredDriverSet);
159 if (isReady && !isStarted) {
160 log.info("Starting driver subsystem");
161 componenService.activate(null, DRIVER_COMPONENT);
162 isStarted = true;
163 } else if (!isReady && isStarted) {
164 log.info("Stopping driver subsystem");
165 componenService.deactivate(null, DRIVER_COMPONENT);
166 isStarted = false;
167 }
168 }
169
170 private Set<String> registeredDrivers() {
171 ImmutableSet.Builder<String> builder = ImmutableSet.builder();
172 for (DriverProvider dp : providers) {
173 dp.getDrivers().stream().map(Driver::name).forEach(builder::add);
174 }
175 return builder.build();
176 }
177
178 @Override
179 public Class<? extends Behaviour> getBehaviourClass(String className) {
180 return classes.get(className);
181 }
182
183 @Override
184 public Set<Driver> getDrivers() {
185 checkPermission(DRIVER_READ);
186 ImmutableSet.Builder<Driver> builder = ImmutableSet.builder();
187 drivers.values().forEach(builder::add);
188 return builder.build();
189 }
190
191 @Override
192 public Driver getDriver(String mfr, String hw, String sw) {
193 checkPermission(DRIVER_READ);
194
195 // First attempt a literal search.
196 Driver driver = driverByKey.get(key(mfr, hw, sw));
197 if (driver != null) {
198 return driver;
199 }
200
201 // Otherwise, sweep through the key space and attempt to match using
202 // regular expression matching.
203 Optional<Driver> optional = driverByKey.values().stream()
204 .filter(d -> matches(d, mfr, hw, sw)).findFirst();
205
206 // If no matching driver is found, return default.
207 return optional.orElse(drivers.get(DEFAULT));
208 }
209
210 @Override
211 public Driver getDriver(String driverName) {
212 checkPermission(DRIVER_READ);
213 return nullIsNotFound(drivers.get(driverName), NO_DRIVER);
214 }
215
216 // Matches the given driver using ERE matching against the given criteria.
217 private boolean matches(Driver d, String mfr, String hw, String sw) {
218 // TODO: consider pre-compiling the expressions in the future
219 return mfr.matches(d.manufacturer()) &&
220 hw.matches(d.hwVersion()) &&
221 sw.matches(d.swVersion());
222 }
223
224 // Produces a composite driver key using the specified components.
225 static String key(String mfr, String hw, String sw) {
226 return String.format("%s-%s-%s", mfr, hw, sw);
227 }
228}