Thomas Vachuska
Committed by Gerrit Code Review

Device driver framework enhancements and CLI.

Change-Id: I5dea67620259797eff89a985718934034a86d63e
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.cli.net;
import org.apache.karaf.shell.console.Completer;
import org.apache.karaf.shell.console.completer.StringsCompleter;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.driver.DriverAdminService;
import java.util.List;
import java.util.SortedSet;
/**
* Device driver name completer.
*/
public class DriverNameCompleter implements Completer {
@Override
public int complete(String buffer, int cursor, List<String> candidates) {
// Delegate string completer
StringsCompleter delegate = new StringsCompleter();
SortedSet<String> strings = delegate.getStrings();
// Fetch our service and feed it's offerings to the string completer
DriverAdminService service = AbstractShellCommand.get(DriverAdminService.class);
service.getDrivers().forEach(d -> strings.add(d.name()));
// Now let the completer do the work for figuring out what to offer.
return delegate.complete(buffer, cursor, candidates);
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.cli.net;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.driver.Driver;
import org.onosproject.net.driver.DriverAdminService;
/**
* Lists device drivers.
*/
@Command(scope = "onos", name = "drivers",
description = "Lists device drivers")
public class DriversListCommand extends AbstractShellCommand {
private static final String FMT = "driver=%s, mfr=%s, hw=%s, sw=%s";
private static final String FMT_B = " %s via %s";
private static final String FMT_P = " %s=%s";
@Argument(index = 0, name = "driverName", description = "Driver name",
required = false, multiValued = false)
String driverName = null;
@Override
protected void execute() {
DriverAdminService service = get(DriverAdminService.class);
if (driverName != null) {
printDriver(service.getDriver(driverName));
} else {
service.getDrivers().forEach(this::printDriver);
}
}
private void printDriver(Driver driver) {
print(FMT, driver.name(), driver.manufacturer(),
driver.hwVersion(), driver.swVersion());
driver.behaviours().forEach(b -> print(FMT_B, b.getCanonicalName(),
driver.implementation(b).getCanonicalName()));
driver.properties().forEach((k, v) -> print(FMT_P, k, v));
}
}
......@@ -71,6 +71,14 @@
</command>
<command>
<action class="org.onosproject.cli.net.DriversListCommand"/>
<completers>
<ref component-id="driverNameCompleter"/>
<null/>
</completers>
</command>
<command>
<action class="org.onosproject.cli.net.DevicesListCommand"/>
</command>
<command>
......@@ -316,5 +324,6 @@
<bean id="nullCompleter" class="org.apache.karaf.shell.console.completer.NullCompleter"/>
<bean id="ethTypeCompleter" class="org.onosproject.cli.net.EthTypeCompleter"/>
<bean id="ipProtocolCompleter" class="org.onosproject.cli.net.IpProtocolCompleter"/>
<bean id="driverNameCompleter" class="org.onosproject.cli.net.DriverNameCompleter"/>
</blueprint>
......
......@@ -69,15 +69,17 @@ public class DefaultDriver implements Driver {
* @param other other driver
* @return new driver
*/
DefaultDriver merge(DefaultDriver other) {
@Override
public Driver merge(Driver other) {
// Merge the behaviours.
ImmutableMap.Builder<Class<? extends Behaviour>, Class<? extends Behaviour>>
behaviours = ImmutableMap.builder();
behaviours.putAll(other.behaviours).putAll(this.behaviours);
behaviours.putAll(this.behaviours);
other.behaviours().forEach(b -> behaviours.put(b, other.implementation(b)));
// Merge the properties.
ImmutableMap.Builder<String, String> properties = ImmutableMap.builder();
properties.putAll(other.properties).putAll(this.properties);
properties.putAll(this.properties).putAll(other.properties());
return new DefaultDriver(name, manufacturer, hwVersion, swVersion,
behaviours.build(), properties.build());
......@@ -109,6 +111,11 @@ public class DefaultDriver implements Driver {
}
@Override
public Class<? extends Behaviour> implementation(Class<? extends Behaviour> behaviour) {
return behaviours.get(behaviour);
}
@Override
public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) {
return behaviours.containsKey(behaviourClass);
}
......
......@@ -16,8 +16,8 @@
package org.onosproject.net.driver;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
......@@ -28,7 +28,7 @@ import static com.google.common.base.MoreObjects.toStringHelper;
*/
public class DefaultDriverProvider implements DriverProvider {
private final Map<String, DefaultDriver> drivers = new HashMap<>();
protected final Map<String, Driver> drivers = Maps.newConcurrentMap();
@Override
public Set<Driver> getDrivers() {
......@@ -36,32 +36,49 @@ public class DefaultDriverProvider implements DriverProvider {
}
/**
* Adds the specified driver to be provided.
* Adds the specified drivers to the provider.
*
* @param driverClasses driver to be provided
* @param drivers drivers to be added
*/
public void addDrivers(Set<DefaultDriver> driverClasses) {
for (DefaultDriver driverClass : driverClasses) {
addDriver(driverClass);
}
public void addDrivers(Set<Driver> drivers) {
drivers.forEach(this::addDriver);
}
/**
* Adds the specified driver to be provided.
* Adds the specified driver to the provider.
*
* @param driverClass driver to be provided
* @param driver driver to be provided
*/
public void addDriver(DefaultDriver driverClass) {
DefaultDriver ddc = drivers.get(driverClass.name());
public void addDriver(Driver driver) {
Driver ddc = drivers.get(driver.name());
if (ddc == null) {
// If we don't have the driver yet, just use the new one.
drivers.put(driverClass.name(), driverClass);
drivers.put(driver.name(), driver);
} else {
// Otherwise merge the existing driver with the new one and rebind.
drivers.put(driverClass.name(), ddc.merge(driverClass));
drivers.put(driver.name(), ddc.merge(driver));
}
}
/**
* Removes the specified drivers from the provider.
*
* @param drivers drivers to be removed
*/
public void removeDrivers(Set<Driver> drivers) {
drivers.forEach(this::removeDriver);
}
/**
* Removes the specified driver from the provider.
*
* @param driver driver to be removed
*/
public void removeDriver(Driver driver) {
// TODO: make selective if possible
drivers.remove(driver.name());
}
@Override
public String toString() {
return toStringHelper(this).add("drivers", drivers).toString();
......
......@@ -63,6 +63,14 @@ public interface Driver extends Annotations {
Set<Class<? extends Behaviour>> behaviours();
/**
* Returns the implementation class for the specified behaviour.
*
* @param behaviour behaviour interface
* @return implementation class
*/
Class<? extends Behaviour> implementation(Class<? extends Behaviour> behaviour);
/**
* Indicates whether or not the driver supports the specified class
* of behaviour.
*
......@@ -90,4 +98,13 @@ public interface Driver extends Annotations {
*/
Map<String, String> properties();
/**
* Merges the specified driver behaviours and properties into this one,
* giving preference to the other driver when dealing with conflicts.
*
* @param other other driver
* @return merged driver
*/
Driver merge(Driver other);
}
......
......@@ -25,13 +25,19 @@ import java.util.Set;
public interface DriverService {
/**
* Returns the overall set of drivers being provided, optionally
* filtered to only those that support all specified behaviours.
* Returns the overall set of drivers being provided.
*
* @param withBehaviours optional behaviour classes to query by
* @return provided drivers
*/
Set<Driver> getDrivers(Class<? extends Behaviour>... withBehaviours);
Set<Driver> getDrivers();
/**
* Returns the set of drivers which support the specified behaviour.
*
* @param withBehaviour behaviour class to query by
* @return provided drivers
*/
Set<Driver> getDrivers(Class<? extends Behaviour> withBehaviour);
/**
* Returns the specified driver.
......
......@@ -50,7 +50,7 @@ public class DefaultDriverTest {
ImmutableMap.of(TestBehaviour.class,
TestBehaviourImpl.class),
ImmutableMap.of("foo", "bar"));
DefaultDriver ddc =
Driver ddc =
one.merge(new DefaultDriver("foo.bar", "", "", "",
ImmutableMap.of(TestBehaviourTwo.class,
TestBehaviourTwoImpl.class),
......
......@@ -30,6 +30,7 @@ import org.onosproject.net.device.DeviceService;
import org.onosproject.net.driver.Behaviour;
import org.onosproject.net.driver.DefaultDriverData;
import org.onosproject.net.driver.DefaultDriverHandler;
import org.onosproject.net.driver.DefaultDriverProvider;
import org.onosproject.net.driver.Driver;
import org.onosproject.net.driver.DriverAdminService;
import org.onosproject.net.driver.DriverHandler;
......@@ -40,6 +41,7 @@ import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static org.onlab.util.Tools.nullIsNotFound;
import static org.onosproject.net.AnnotationKeys.DRIVER;
......@@ -49,7 +51,7 @@ import static org.onosproject.net.AnnotationKeys.DRIVER;
*/
@Component(immediate = true)
@Service
public class DriverManager implements DriverAdminService {
public class DriverManager extends DefaultDriverProvider implements DriverAdminService {
private final Logger log = LoggerFactory.getLogger(getClass());
......@@ -61,7 +63,6 @@ public class DriverManager implements DriverAdminService {
protected DeviceService deviceService;
private Set<DriverProvider> providers = Sets.newConcurrentHashSet();
private Map<String, Driver> driverByName = Maps.newConcurrentMap();
private Map<String, Driver> driverByKey = Maps.newConcurrentMap();
@Activate
......@@ -83,7 +84,7 @@ public class DriverManager implements DriverAdminService {
@Override
public void registerProvider(DriverProvider provider) {
provider.getDrivers().forEach(driver -> {
driverByName.put(driver.name(), driver);
addDrivers(provider.getDrivers());
driverByKey.put(key(driver.manufacturer(),
driver.hwVersion(),
driver.swVersion()), driver);
......@@ -94,7 +95,7 @@ public class DriverManager implements DriverAdminService {
@Override
public void unregisterProvider(DriverProvider provider) {
provider.getDrivers().forEach(driver -> {
driverByName.remove(driver.name());
removeDrivers(provider.getDrivers());
driverByKey.remove(key(driver.manufacturer(),
driver.hwVersion(),
driver.swVersion()));
......@@ -103,21 +104,22 @@ public class DriverManager implements DriverAdminService {
}
@Override
public Set<Driver> getDrivers(Class<? extends Behaviour>... withBehaviours) {
public Set<Driver> getDrivers() {
ImmutableSet.Builder<Driver> builder = ImmutableSet.builder();
for (Class<? extends Behaviour> behaviour : withBehaviours) {
driverByName.forEach((name, driver) -> {
if (driver.hasBehaviour(behaviour)) {
builder.add(driver);
}
});
}
drivers.values().forEach(builder::add);
return builder.build();
}
@Override
public Set<Driver> getDrivers(Class<? extends Behaviour> withBehaviour) {
return drivers.values().stream()
.filter(d -> d.hasBehaviour(withBehaviour))
.collect(Collectors.toSet());
}
@Override
public Driver getDriver(String driverName) {
return nullIsNotFound(driverByName.get(driverName), NO_DRIVER);
return nullIsNotFound(drivers.get(driverName), NO_DRIVER);
}
@Override
......@@ -134,7 +136,7 @@ public class DriverManager implements DriverAdminService {
.filter(d -> matches(d, mfr, hw, sw)).findFirst();
// If no matching driver is found, return default.
return optional.isPresent() ? optional.get() : driverByName.get(DEFAULT);
return optional.isPresent() ? optional.get() : drivers.get(DEFAULT);
}
// Matches the given driver using ERE matching against the given criteria.
......@@ -163,6 +165,7 @@ public class DriverManager implements DriverAdminService {
return new DefaultDriverHandler(new DefaultDriverData(driver));
}
// Produces a composite driver key using the specified components.
private String key(String mfr, String hw, String sw) {
return String.format("%s-%s-%s", mfr, hw, sw);
}
......
......@@ -21,7 +21,7 @@ import org.onosproject.core.DefaultGroupId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.behaviour.Pipeliner;
import org.onosproject.net.behaviour.PipelinerContext;
import org.onosproject.net.driver.DriverData;
import org.onosproject.net.driver.AbstractBehaviour;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleOperations;
......@@ -41,7 +41,7 @@ import static org.slf4j.LoggerFactory.getLogger;
/**
* Simple single table pipeline abstraction.
*/
public class DefaultSingleTablePipeline implements Pipeliner {
public class DefaultSingleTablePipeline extends AbstractBehaviour implements Pipeliner {
private final Logger log = getLogger(getClass());
......@@ -89,7 +89,7 @@ public class DefaultSingleTablePipeline implements Pipeliner {
flowBuilder.remove(rule);
break;
default:
log.warn("Unknown operation {}", fwd.op());
log.warn("Unknown operation {}", fwd.op());
}
});
......@@ -115,8 +115,4 @@ public class DefaultSingleTablePipeline implements Pipeliner {
throw new UnsupportedOperationException("Single table does not next hop.");
}
@Override
public void setData(DriverData data) {
}
}
......
......@@ -24,7 +24,7 @@ import org.onosproject.core.CoreService;
import org.onosproject.net.DeviceId;
import org.onosproject.net.behaviour.Pipeliner;
import org.onosproject.net.behaviour.PipelinerContext;
import org.onosproject.net.driver.DriverData;
import org.onosproject.net.driver.AbstractBehaviour;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
......@@ -45,9 +45,9 @@ import java.util.concurrent.Future;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Created by ash on 07/04/15.
* Corsa pipeline handler.
*/
public class OVSCorsaPipeline implements Pipeliner {
public class OVSCorsaPipeline extends AbstractBehaviour implements Pipeliner {
private static final int CONTROLLER_PRIORITY = 255;
private static final int DROP_PRIORITY = 0;
......@@ -92,12 +92,6 @@ public class OVSCorsaPipeline implements Pipeliner {
return null;
}
@Override
public void setData(DriverData data) {
}
private void pushDefaultRules() {
boolean install = true;
processTableZero(install);
......@@ -130,7 +124,6 @@ public class OVSCorsaPipeline implements Pipeliner {
ops = install ? ops.add(rule) : ops.remove(rule);
//Drop rule
selector = DefaultTrafficSelector.builder();
treatment = DefaultTrafficTreatment.builder();
......@@ -195,7 +188,6 @@ public class OVSCorsaPipeline implements Pipeliner {
FlowRule rule;
//Drop rule
selector = DefaultTrafficSelector.builder();
treatment = DefaultTrafficTreatment.builder();
......