mirror of
https://github.com/opennetworkinglab/onos.git
synced 2026-05-05 04:06:49 +02:00
Devices,hosts, and links can be blocked and kicked off with the network configuration api
Change-Id: I68d427f4886a7b63475df8d35383e2e347946946
This commit is contained in:
parent
b745ca6619
commit
3a0cdd57e7
@ -76,6 +76,18 @@ public class DefaultDeviceDescription extends AbstractDescription
|
||||
base.chassisId(), annotations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a device description using the supplied information.
|
||||
* @param base DeviceDescription to basic information (except for type)
|
||||
* @param type device type
|
||||
* @param annotations Annotations to use.
|
||||
*/
|
||||
public DefaultDeviceDescription(DeviceDescription base, Type type, SparseAnnotations... annotations) {
|
||||
this(base.deviceURI(), type, base.manufacturer(),
|
||||
base.hwVersion(), base.swVersion(), base.serialNumber(),
|
||||
base.chassisId(), annotations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI deviceURI() {
|
||||
return uri;
|
||||
|
||||
@ -39,4 +39,12 @@ public interface LinkAdminService extends LinkService {
|
||||
*/
|
||||
void removeLinks(DeviceId deviceId);
|
||||
|
||||
/**
|
||||
* Removes all links between between the specified src and
|
||||
* dst connection points.
|
||||
*
|
||||
* @param src link source
|
||||
* @param dst link destination
|
||||
*/
|
||||
void removeLink(ConnectPoint src, ConnectPoint dst);
|
||||
}
|
||||
|
||||
@ -58,12 +58,25 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onos-incubator-api</artifactId>
|
||||
<scope>test</scope>
|
||||
<classifier>tests</classifier>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.easymock</groupId>
|
||||
<artifactId>easymock</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.onosproject</groupId>
|
||||
<artifactId>onos-incubator-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>org.apache.felix.scr.annotations</artifactId>
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
package org.onosproject.net.device.impl;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
|
||||
import static org.onlab.util.Tools.groupedThreads;
|
||||
import static org.onosproject.net.MastershipRole.MASTER;
|
||||
@ -45,17 +46,23 @@ import org.onosproject.cluster.NodeId;
|
||||
import org.onosproject.core.Permission;
|
||||
import org.onosproject.event.EventDeliveryService;
|
||||
import org.onosproject.event.ListenerRegistry;
|
||||
import org.onosproject.incubator.net.config.NetworkConfigEvent;
|
||||
import org.onosproject.incubator.net.config.NetworkConfigListener;
|
||||
import org.onosproject.incubator.net.config.NetworkConfigService;
|
||||
import org.onosproject.incubator.net.config.basics.BasicDeviceConfig;
|
||||
import org.onosproject.mastership.MastershipEvent;
|
||||
import org.onosproject.mastership.MastershipListener;
|
||||
import org.onosproject.mastership.MastershipService;
|
||||
import org.onosproject.mastership.MastershipTerm;
|
||||
import org.onosproject.mastership.MastershipTermService;
|
||||
import org.onosproject.net.DefaultAnnotations;
|
||||
import org.onosproject.net.Device;
|
||||
import org.onosproject.net.Device.Type;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.MastershipRole;
|
||||
import org.onosproject.net.Port;
|
||||
import org.onosproject.net.PortNumber;
|
||||
import org.onosproject.net.SparseAnnotations;
|
||||
import org.onosproject.net.device.DefaultDeviceDescription;
|
||||
import org.onosproject.net.device.DefaultPortDescription;
|
||||
import org.onosproject.net.device.DeviceAdminService;
|
||||
@ -104,6 +111,8 @@ public class DeviceManager
|
||||
|
||||
private ScheduledExecutorService backgroundService;
|
||||
|
||||
private final NetworkConfigListener networkConfigListener = new InternalNetworkConfigListener();
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected DeviceStore store;
|
||||
|
||||
@ -122,6 +131,11 @@ public class DeviceManager
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected DeviceClockProviderService deviceClockProviderService;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected NetworkConfigService networkConfigService;
|
||||
|
||||
|
||||
|
||||
@Activate
|
||||
public void activate() {
|
||||
backgroundService = newSingleThreadScheduledExecutor(groupedThreads("onos/device", "manager-background"));
|
||||
@ -130,6 +144,7 @@ public class DeviceManager
|
||||
store.setDelegate(delegate);
|
||||
eventDispatcher.addSink(DeviceEvent.class, listenerRegistry);
|
||||
mastershipService.addListener(mastershipListener);
|
||||
networkConfigService.addListener(networkConfigListener);
|
||||
|
||||
backgroundService.scheduleWithFixedDelay(new Runnable() {
|
||||
|
||||
@ -148,7 +163,7 @@ public class DeviceManager
|
||||
@Deactivate
|
||||
public void deactivate() {
|
||||
backgroundService.shutdown();
|
||||
|
||||
networkConfigService.removeListener(networkConfigListener);
|
||||
store.unsetDelegate(delegate);
|
||||
mastershipService.removeListener(mastershipListener);
|
||||
eventDispatcher.removeSink(DeviceEvent.class);
|
||||
@ -286,7 +301,8 @@ public class DeviceManager
|
||||
continue;
|
||||
}
|
||||
|
||||
log.info("{} is reachable but did not have a valid role, reasserting", deviceId);
|
||||
log.info("{} is reachable but did not have a valid role, reasserting",
|
||||
deviceId);
|
||||
|
||||
// isReachable but was not MASTER or STANDBY, get a role and apply
|
||||
// Note: NONE triggers request to MastershipService
|
||||
@ -319,7 +335,8 @@ public class DeviceManager
|
||||
|
||||
DeviceProvider provider = provider();
|
||||
if (provider == null) {
|
||||
log.warn("Provider for {} was not found. Cannot apply role {}", deviceId, newRole);
|
||||
log.warn("Provider for {} was not found. Cannot apply role {}",
|
||||
deviceId, newRole);
|
||||
return false;
|
||||
}
|
||||
provider.roleChanged(deviceId, newRole);
|
||||
@ -335,8 +352,8 @@ public class DeviceManager
|
||||
checkNotNull(deviceId, DEVICE_ID_NULL);
|
||||
checkNotNull(deviceDescription, DEVICE_DESCRIPTION_NULL);
|
||||
checkValidity();
|
||||
deviceDescription = validateDevice(deviceDescription, deviceId);
|
||||
|
||||
log.info("Device {} connected", deviceId);
|
||||
// check my Role
|
||||
CompletableFuture<MastershipRole> role = mastershipService.requestRoleFor(deviceId);
|
||||
try {
|
||||
@ -362,16 +379,33 @@ public class DeviceManager
|
||||
deviceClockProviderService.setMastershipTerm(deviceId, term);
|
||||
applyRole(deviceId, MastershipRole.MASTER);
|
||||
}
|
||||
|
||||
DeviceEvent event = store.createOrUpdateDevice(provider().id(),
|
||||
deviceId, deviceDescription);
|
||||
|
||||
DeviceEvent event = store.createOrUpdateDevice(provider().id(), deviceId,
|
||||
deviceDescription);
|
||||
if (event != null) {
|
||||
log.trace("event: {} {}", event.type(), event);
|
||||
post(event);
|
||||
}
|
||||
}
|
||||
|
||||
// returns a DeviceDescription made from the union of the BasicDeviceConfig
|
||||
// annotations if it exists
|
||||
private DeviceDescription validateDevice(DeviceDescription deviceDescription, DeviceId deviceId) {
|
||||
BasicDeviceConfig cfg = networkConfigService.getConfig(deviceId, BasicDeviceConfig.class);
|
||||
checkState(cfg == null || cfg.isAllowed(), "Device " + deviceId + " is not allowed");
|
||||
log.info("Device {} connected", deviceId);
|
||||
if (cfg != null) {
|
||||
SparseAnnotations finalSparse = processAnnotations(cfg, deviceDescription, deviceId);
|
||||
if (cfg.type() != Type.SWITCH) {
|
||||
deviceDescription = new DefaultDeviceDescription(deviceDescription,
|
||||
cfg.type(), finalSparse);
|
||||
} else {
|
||||
deviceDescription = new DefaultDeviceDescription(deviceDescription,
|
||||
deviceDescription.type(), finalSparse);
|
||||
}
|
||||
}
|
||||
return deviceDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deviceDisconnected(DeviceId deviceId) {
|
||||
checkNotNull(deviceId, DEVICE_ID_NULL);
|
||||
@ -433,7 +467,7 @@ public class DeviceManager
|
||||
List<PortDescription> portDescriptions) {
|
||||
checkNotNull(deviceId, DEVICE_ID_NULL);
|
||||
checkNotNull(portDescriptions,
|
||||
"Port descriptions list cannot be null");
|
||||
"Port descriptions list cannot be null");
|
||||
checkValidity();
|
||||
if (!deviceClockProviderService.isTimestampAvailable(deviceId)) {
|
||||
// Never been a master for this device
|
||||
@ -459,7 +493,8 @@ public class DeviceManager
|
||||
if (!deviceClockProviderService.isTimestampAvailable(deviceId)) {
|
||||
// Never been a master for this device
|
||||
// any update will be ignored.
|
||||
log.trace("Ignoring {} port update on standby node. {}", deviceId, portDescription);
|
||||
log.trace("Ignoring {} port update on standby node. {}", deviceId,
|
||||
portDescription);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -486,7 +521,7 @@ public class DeviceManager
|
||||
// FIXME: implement response to this notification
|
||||
|
||||
log.debug("got reply to a role request for {}: asked for {}, and got {}",
|
||||
deviceId, requested, response);
|
||||
deviceId, requested, response);
|
||||
|
||||
if (requested == null && response == null) {
|
||||
// something was off with DeviceProvider, maybe check channel too?
|
||||
@ -525,6 +560,37 @@ public class DeviceManager
|
||||
deviceId, portStatistics);
|
||||
post(event);
|
||||
}
|
||||
|
||||
// supplements or replaces deviceDescription annotations with
|
||||
// BasicDeviceConfig annotations
|
||||
private SparseAnnotations processAnnotations(BasicDeviceConfig cfg, DeviceDescription deviceDescription,
|
||||
DeviceId deviceId) {
|
||||
SparseAnnotations originalAnnotations = deviceDescription.annotations();
|
||||
DefaultAnnotations.Builder newBuilder = DefaultAnnotations.builder();
|
||||
if (cfg.driver() != deviceId.toString()) {
|
||||
newBuilder.set(cfg.DRIVER, cfg.driver());
|
||||
}
|
||||
if (cfg.type() != Type.SWITCH) {
|
||||
newBuilder.set(cfg.TYPE, cfg.type().toString());
|
||||
}
|
||||
if (cfg.name() != null) {
|
||||
newBuilder.set(cfg.NAME, cfg.name());
|
||||
}
|
||||
if (cfg.latitude() != -1) {
|
||||
newBuilder.set(cfg.LATITUDE, Double.toString(cfg.latitude()));
|
||||
}
|
||||
if (cfg.longitude() != -1) {
|
||||
newBuilder.set(cfg.LONGITUDE, Double.toString(cfg.longitude()));
|
||||
}
|
||||
if (cfg.rackAddress() != null) {
|
||||
newBuilder.set(cfg.RACK_ADDRESS, cfg.rackAddress());
|
||||
}
|
||||
if (cfg.owner() != null) {
|
||||
newBuilder.set(cfg.OWNER, cfg.owner());
|
||||
}
|
||||
DefaultAnnotations newAnnotations = newBuilder.build();
|
||||
return DefaultAnnotations.union(originalAnnotations, newAnnotations);
|
||||
}
|
||||
}
|
||||
|
||||
// Posts the specified event to the local event dispatcher.
|
||||
@ -727,4 +793,30 @@ public class DeviceManager
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private class InternalNetworkConfigListener implements NetworkConfigListener {
|
||||
@Override
|
||||
public void event(NetworkConfigEvent event) {
|
||||
if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
|
||||
event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
|
||||
event.configClass().equals(BasicDeviceConfig.class)) {
|
||||
log.info("Detected Device network config event {}", event.type());
|
||||
kickOutBadDevice(((DeviceId) event.subject()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checks if the specified device is allowed by the BasicDeviceConfig
|
||||
// and if not, removes it
|
||||
private void kickOutBadDevice(DeviceId deviceId) {
|
||||
BasicDeviceConfig cfg = networkConfigService.getConfig(deviceId, BasicDeviceConfig.class);
|
||||
if (!cfg.isAllowed()) {
|
||||
Device badDevice = getDevice(deviceId);
|
||||
if (badDevice != null) {
|
||||
removeDevice(deviceId);
|
||||
} else {
|
||||
log.info("Failed removal: Device {} does not exist", deviceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,11 +27,18 @@ import org.onlab.packet.VlanId;
|
||||
import org.onosproject.core.Permission;
|
||||
import org.onosproject.event.EventDeliveryService;
|
||||
import org.onosproject.event.ListenerRegistry;
|
||||
import org.onosproject.incubator.net.config.NetworkConfigEvent;
|
||||
import org.onosproject.incubator.net.config.NetworkConfigListener;
|
||||
import org.onosproject.incubator.net.config.NetworkConfigService;
|
||||
import org.onosproject.incubator.net.config.basics.BasicHostConfig;
|
||||
import org.onosproject.net.ConnectPoint;
|
||||
import org.onosproject.net.DefaultAnnotations;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.Host;
|
||||
import org.onosproject.net.HostId;
|
||||
import org.onosproject.net.SparseAnnotations;
|
||||
import org.onosproject.net.device.DeviceService;
|
||||
import org.onosproject.net.host.DefaultHostDescription;
|
||||
import org.onosproject.net.host.HostAdminService;
|
||||
import org.onosproject.net.host.HostDescription;
|
||||
import org.onosproject.net.host.HostEvent;
|
||||
@ -51,6 +58,7 @@ import org.slf4j.Logger;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
import static org.onosproject.security.AppGuard.checkPermission;
|
||||
|
||||
@ -70,6 +78,8 @@ public class HostManager
|
||||
private final ListenerRegistry<HostEvent, HostListener>
|
||||
listenerRegistry = new ListenerRegistry<>();
|
||||
|
||||
private final NetworkConfigListener networkConfigListener = new InternalNetworkConfigListener();
|
||||
|
||||
private HostStoreDelegate delegate = new InternalStoreDelegate();
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
@ -84,6 +94,9 @@ public class HostManager
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected PacketService packetService;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected NetworkConfigService networkConfigService;
|
||||
|
||||
private HostMonitor monitor;
|
||||
|
||||
@Activate
|
||||
@ -91,7 +104,7 @@ public class HostManager
|
||||
log.info("Started");
|
||||
store.setDelegate(delegate);
|
||||
eventDispatcher.addSink(HostEvent.class, listenerRegistry);
|
||||
|
||||
networkConfigService.addListener(networkConfigListener);
|
||||
monitor = new HostMonitor(deviceService, packetService, this);
|
||||
monitor.start();
|
||||
}
|
||||
@ -100,6 +113,7 @@ public class HostManager
|
||||
public void deactivate() {
|
||||
store.unsetDelegate(delegate);
|
||||
eventDispatcher.removeSink(HostEvent.class);
|
||||
networkConfigService.removeListener(networkConfigListener);
|
||||
log.info("Stopped");
|
||||
}
|
||||
|
||||
@ -246,7 +260,6 @@ public class HostManager
|
||||
private class InternalHostProviderService
|
||||
extends AbstractProviderService<HostProvider>
|
||||
implements HostProviderService {
|
||||
|
||||
InternalHostProviderService(HostProvider provider) {
|
||||
super(provider);
|
||||
}
|
||||
@ -255,6 +268,7 @@ public class HostManager
|
||||
public void hostDetected(HostId hostId, HostDescription hostDescription) {
|
||||
checkNotNull(hostId, HOST_ID_NULL);
|
||||
checkValidity();
|
||||
hostDescription = validateHost(hostDescription, hostId);
|
||||
HostEvent event = store.createOrUpdateHost(provider().id(), hostId,
|
||||
hostDescription);
|
||||
if (event != null) {
|
||||
@ -262,6 +276,21 @@ public class HostManager
|
||||
}
|
||||
}
|
||||
|
||||
// returns a HostDescription made from the union of the BasicHostConfig
|
||||
// annotations if it exists
|
||||
private HostDescription validateHost(HostDescription hostDescription, HostId hostId) {
|
||||
BasicHostConfig cfg = networkConfigService.getConfig(hostId, BasicHostConfig.class);
|
||||
checkState(cfg == null || cfg.isAllowed(), "Host {} is not allowed", hostId);
|
||||
if (cfg != null) {
|
||||
SparseAnnotations finalSparse = processAnnotations(cfg, hostDescription);
|
||||
hostDescription = new DefaultHostDescription(hostId.mac(),
|
||||
hostDescription.vlan(),
|
||||
hostDescription.location(),
|
||||
finalSparse);
|
||||
}
|
||||
return hostDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hostVanished(HostId hostId) {
|
||||
checkNotNull(hostId, HOST_ID_NULL);
|
||||
@ -273,6 +302,30 @@ public class HostManager
|
||||
}
|
||||
}
|
||||
|
||||
// Supplements or replaces hostDescriptions's annotations with BasicHostConfig's
|
||||
// annotations
|
||||
private SparseAnnotations processAnnotations(BasicHostConfig cfg, HostDescription hostDescription) {
|
||||
SparseAnnotations originalAnnotations = hostDescription.annotations();
|
||||
DefaultAnnotations.Builder newBuilder = DefaultAnnotations.builder();
|
||||
if (cfg.name() != null) {
|
||||
newBuilder.set(cfg.NAME, cfg.name());
|
||||
}
|
||||
if (cfg.latitude() != -1) {
|
||||
newBuilder.set(cfg.LATITUDE, Double.toString(cfg.latitude()));
|
||||
}
|
||||
if (cfg.longitude() != -1) {
|
||||
newBuilder.set(cfg.LONGITUDE, Double.toString(cfg.longitude()));
|
||||
}
|
||||
if (cfg.rackAddress() != null) {
|
||||
newBuilder.set(cfg.RACK_ADDRESS, cfg.rackAddress());
|
||||
}
|
||||
if (cfg.owner() != null) {
|
||||
newBuilder.set(cfg.OWNER, cfg.owner());
|
||||
}
|
||||
DefaultAnnotations newAnnotations = newBuilder.build();
|
||||
return DefaultAnnotations.union(originalAnnotations, newAnnotations);
|
||||
}
|
||||
|
||||
// Posts the specified event to the local event dispatcher.
|
||||
private void post(HostEvent event) {
|
||||
if (event != null) {
|
||||
@ -287,4 +340,32 @@ public class HostManager
|
||||
post(event);
|
||||
}
|
||||
}
|
||||
|
||||
// listens for NetworkConfigEvents of type BasicHostConfig and removes
|
||||
// links that the config does not allow
|
||||
private class InternalNetworkConfigListener implements NetworkConfigListener {
|
||||
@Override
|
||||
public void event(NetworkConfigEvent event) {
|
||||
if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
|
||||
event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
|
||||
event.configClass().equals(BasicHostConfig.class)) {
|
||||
log.info("Detected Host network config event {}", event.type());
|
||||
kickOutBadHost(((HostId) event.subject()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checks if the specified host is allowed by the BasicHostConfig
|
||||
// and if not, removes it
|
||||
private void kickOutBadHost(HostId hostId) {
|
||||
BasicHostConfig cfg = networkConfigService.getConfig(hostId, BasicHostConfig.class);
|
||||
if (cfg != null && !cfg.isAllowed()) {
|
||||
Host badHost = getHost(hostId);
|
||||
if (badHost != null) {
|
||||
removeHost(hostId);
|
||||
} else {
|
||||
log.info("Failed removal: Host {} does not exist", hostId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,14 +27,22 @@ import org.apache.felix.scr.annotations.Service;
|
||||
import org.onosproject.core.Permission;
|
||||
import org.onosproject.event.EventDeliveryService;
|
||||
import org.onosproject.event.ListenerRegistry;
|
||||
import org.onosproject.incubator.net.config.NetworkConfigEvent;
|
||||
import org.onosproject.incubator.net.config.NetworkConfigListener;
|
||||
import org.onosproject.incubator.net.config.NetworkConfigService;
|
||||
import org.onosproject.incubator.net.config.basics.BasicLinkConfig;
|
||||
import org.onosproject.net.ConnectPoint;
|
||||
import org.onosproject.net.DefaultAnnotations;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.Link;
|
||||
import org.onosproject.net.Link.State;
|
||||
import org.onosproject.net.LinkKey;
|
||||
import org.onosproject.net.MastershipRole;
|
||||
import org.onosproject.net.SparseAnnotations;
|
||||
import org.onosproject.net.device.DeviceEvent;
|
||||
import org.onosproject.net.device.DeviceListener;
|
||||
import org.onosproject.net.device.DeviceService;
|
||||
import org.onosproject.net.link.DefaultLinkDescription;
|
||||
import org.onosproject.net.link.LinkAdminService;
|
||||
import org.onosproject.net.link.LinkDescription;
|
||||
import org.onosproject.net.link.LinkEvent;
|
||||
@ -49,9 +57,12 @@ import org.onosproject.net.provider.AbstractProviderRegistry;
|
||||
import org.onosproject.net.provider.AbstractProviderService;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static org.onosproject.net.LinkKey.linkKey;
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
import static org.onosproject.security.AppGuard.checkPermission;
|
||||
|
||||
@ -78,6 +89,8 @@ public class LinkManager
|
||||
|
||||
private final DeviceListener deviceListener = new InternalDeviceListener();
|
||||
|
||||
private final NetworkConfigListener networkConfigListener = new InternalNetworkConfigListener();
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected LinkStore store;
|
||||
|
||||
@ -87,11 +100,15 @@ public class LinkManager
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected EventDeliveryService eventDispatcher;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
protected NetworkConfigService networkConfigService;
|
||||
|
||||
@Activate
|
||||
public void activate() {
|
||||
store.setDelegate(delegate);
|
||||
eventDispatcher.addSink(LinkEvent.class, listenerRegistry);
|
||||
deviceService.addListener(deviceListener);
|
||||
networkConfigService.addListener(networkConfigListener);
|
||||
log.info("Started");
|
||||
}
|
||||
|
||||
@ -100,6 +117,7 @@ public class LinkManager
|
||||
store.unsetDelegate(delegate);
|
||||
eventDispatcher.removeSink(LinkEvent.class);
|
||||
deviceService.removeListener(deviceListener);
|
||||
networkConfigService.removeListener(networkConfigListener);
|
||||
log.info("Stopped");
|
||||
}
|
||||
|
||||
@ -206,17 +224,19 @@ public class LinkManager
|
||||
removeLinks(getDeviceLinks(deviceId), false);
|
||||
}
|
||||
|
||||
public void removeLink(ConnectPoint src, ConnectPoint dst) {
|
||||
post(store.removeLink(src, dst));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(LinkListener listener) {
|
||||
checkPermission(Permission.LINK_EVENT);
|
||||
|
||||
listenerRegistry.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(LinkListener listener) {
|
||||
checkPermission(Permission.LINK_EVENT);
|
||||
|
||||
listenerRegistry.removeListener(listener);
|
||||
}
|
||||
|
||||
@ -229,7 +249,7 @@ public class LinkManager
|
||||
removeLinks(event.subject().id());
|
||||
} else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
|
||||
removeLinks(new ConnectPoint(event.subject().id(),
|
||||
event.port().number()));
|
||||
event.port().number()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -252,15 +272,62 @@ public class LinkManager
|
||||
public void linkDetected(LinkDescription linkDescription) {
|
||||
checkNotNull(linkDescription, LINK_DESC_NULL);
|
||||
checkValidity();
|
||||
|
||||
linkDescription = validateLink(linkDescription);
|
||||
LinkEvent event = store.createOrUpdateLink(provider().id(),
|
||||
linkDescription);
|
||||
linkDescription);
|
||||
if (event != null) {
|
||||
log.info("Link {} detected", linkDescription);
|
||||
post(event);
|
||||
}
|
||||
}
|
||||
|
||||
// returns a LinkDescription made from the union of the BasicLinkConfig
|
||||
// annotations if it exists
|
||||
private LinkDescription validateLink(LinkDescription linkDescription) {
|
||||
// TODO Investigate whether this can be made more efficient
|
||||
BasicLinkConfig cfg = networkConfigService.getConfig(linkKey(linkDescription.src(),
|
||||
linkDescription.dst()),
|
||||
BasicLinkConfig.class);
|
||||
BasicLinkConfig cfgTwo = networkConfigService.getConfig(linkKey(linkDescription.dst(),
|
||||
linkDescription.src()),
|
||||
BasicLinkConfig.class);
|
||||
|
||||
checkState(cfg == null || cfg.isAllowed(), "Link " + linkDescription.toString() + " is not allowed");
|
||||
checkState(cfgTwo == null || cfgTwo.isAllowed(), "Link " + linkDescription.toString() + " is not allowed");
|
||||
if (cfg != null) {
|
||||
SparseAnnotations finalSparse = processAnnotations(cfg, linkDescription);
|
||||
// check whether config has a specified type
|
||||
if (cfg.type() != Link.Type.DIRECT) {
|
||||
linkDescription = new DefaultLinkDescription(linkDescription.src(),
|
||||
linkDescription.dst(),
|
||||
cfg.type(), finalSparse);
|
||||
} else {
|
||||
linkDescription = new DefaultLinkDescription(linkDescription.src(),
|
||||
linkDescription.dst(),
|
||||
linkDescription.type(), finalSparse);
|
||||
}
|
||||
}
|
||||
return linkDescription;
|
||||
}
|
||||
|
||||
// supplements or replaces linkDescriptions's annotations with BasicLinkConfig's
|
||||
// annotations
|
||||
private SparseAnnotations processAnnotations(BasicLinkConfig cfg, LinkDescription linkDescription) {
|
||||
SparseAnnotations originalAnnotations = linkDescription.annotations();
|
||||
DefaultAnnotations.Builder newBuilder = DefaultAnnotations.builder();
|
||||
if (cfg.type() != Link.Type.DIRECT) {
|
||||
newBuilder.set(cfg.TYPE, cfg.type().toString());
|
||||
}
|
||||
if (cfg.latency() != Duration.ofNanos(-1)) {
|
||||
newBuilder.set(cfg.LATENCY, cfg.latency().toString());
|
||||
}
|
||||
if (cfg.bandwidth() != -1) {
|
||||
newBuilder.set(cfg.BANDWIDTH, String.valueOf(cfg.bandwidth()));
|
||||
}
|
||||
DefaultAnnotations newAnnotations = newBuilder.build();
|
||||
return DefaultAnnotations.union(originalAnnotations, newAnnotations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void linkVanished(LinkDescription linkDescription) {
|
||||
checkNotNull(linkDescription, LINK_DESC_NULL);
|
||||
@ -297,7 +364,7 @@ public class LinkManager
|
||||
}
|
||||
|
||||
// Removes all links in the specified set and emits appropriate events.
|
||||
private void removeLinks(Set<Link> links, boolean isSoftRemove) {
|
||||
private void removeLinks(Set<Link> links, boolean isSoftRemove) {
|
||||
for (Link link : links) {
|
||||
LinkEvent event = isSoftRemove ?
|
||||
store.removeOrDownLink(link.src(), link.dst()) :
|
||||
@ -323,4 +390,24 @@ public class LinkManager
|
||||
post(event);
|
||||
}
|
||||
}
|
||||
|
||||
// listens for NetworkConfigEvents of type BasicLinkConfig and removes
|
||||
// links that the config does not allow
|
||||
private class InternalNetworkConfigListener implements NetworkConfigListener {
|
||||
@Override
|
||||
public void event(NetworkConfigEvent event) {
|
||||
if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
|
||||
event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
|
||||
event.configClass().equals(BasicLinkConfig.class)) {
|
||||
log.info("Detected Link network config event {}", event.type());
|
||||
LinkKey lk = (LinkKey) event.subject();
|
||||
BasicLinkConfig cfg = networkConfigService.getConfig(lk, BasicLinkConfig.class);
|
||||
if (cfg != null && !cfg.isAllowed()) {
|
||||
log.info("Kicking out links between {} and {}", lk.src(), lk.dst());
|
||||
removeLink(lk.src(), lk.dst());
|
||||
removeLink(lk.dst(), lk.src());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ import org.onosproject.cluster.DefaultControllerNode;
|
||||
import org.onosproject.cluster.NodeId;
|
||||
import org.onosproject.event.Event;
|
||||
import org.onosproject.common.event.impl.TestEventDispatcher;
|
||||
import org.onosproject.incubator.net.config.NetworkConfigServiceAdapter;
|
||||
import org.onosproject.mastership.MastershipServiceAdapter;
|
||||
import org.onosproject.mastership.MastershipTerm;
|
||||
import org.onosproject.mastership.MastershipTermService;
|
||||
@ -115,8 +116,10 @@ public class DeviceManagerTest {
|
||||
mgr.termService = mastershipManager;
|
||||
mgr.clusterService = new TestClusterService();
|
||||
mgr.deviceClockProviderService = new TestClockProviderService();
|
||||
mgr.networkConfigService = new TestNetworkConfigService();
|
||||
mgr.activate();
|
||||
|
||||
|
||||
service.addListener(listener);
|
||||
|
||||
provider = new TestProvider();
|
||||
@ -349,4 +352,7 @@ public class DeviceManagerTest {
|
||||
return registerdBefore.contains(deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
private class TestNetworkConfigService extends NetworkConfigServiceAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,6 +37,7 @@ import org.onlab.packet.MacAddress;
|
||||
import org.onlab.packet.VlanId;
|
||||
import org.onosproject.event.Event;
|
||||
import org.onosproject.common.event.impl.TestEventDispatcher;
|
||||
import org.onosproject.incubator.net.config.NetworkConfigServiceAdapter;
|
||||
import org.onosproject.net.ConnectPoint;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.Host;
|
||||
@ -123,6 +124,7 @@ public class HostManagerTest {
|
||||
mgr.store = new SimpleHostStore();
|
||||
mgr.eventDispatcher = new TestEventDispatcher();
|
||||
registry = mgr;
|
||||
mgr.networkConfigService = new TestNetworkConfigService();
|
||||
mgr.activate();
|
||||
|
||||
mgr.addListener(listener);
|
||||
@ -520,4 +522,7 @@ public class HostManagerTest {
|
||||
assertTrue(storedAddresses.size() == 2);
|
||||
assertTrue(storedAddresses.equals(Sets.newHashSet(add1, add2)));
|
||||
}
|
||||
|
||||
private class TestNetworkConfigService extends NetworkConfigServiceAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.onosproject.event.Event;
|
||||
import org.onosproject.incubator.net.config.NetworkConfigServiceAdapter;
|
||||
import org.onosproject.net.ConnectPoint;
|
||||
import org.onosproject.net.DefaultDevice;
|
||||
import org.onosproject.net.Device;
|
||||
@ -86,6 +87,7 @@ public class LinkManagerTest {
|
||||
protected DeviceManager devmgr = new TestDeviceManager();
|
||||
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mgr = new LinkManager();
|
||||
@ -95,6 +97,7 @@ public class LinkManagerTest {
|
||||
mgr.store = new SimpleLinkStore();
|
||||
mgr.eventDispatcher = new TestEventDispatcher();
|
||||
mgr.deviceService = devmgr;
|
||||
mgr.networkConfigService = new TestNetworkConfigService();
|
||||
mgr.activate();
|
||||
|
||||
DEVICEIDMAP.put(DID1, DEV1);
|
||||
@ -302,5 +305,6 @@ public class LinkManagerTest {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class TestNetworkConfigService extends NetworkConfigServiceAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,75 @@
|
||||
package org.onosproject.incubator.net.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Test adapter for network configuration service.
|
||||
*/
|
||||
public class NetworkConfigServiceAdapter implements NetworkConfigService {
|
||||
@Override
|
||||
public Set<Class> getSubjectClasses() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubjectFactory getSubjectFactory(String subjectKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubjectFactory getSubjectFactory(Class subjectClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Config> getConfigClass(String subjectKey, String configKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> Set<S> getSubjects(Class<S> subjectClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, C extends Config<S>> Set<S> getSubjects(Class<S> subjectClass, Class<C> configClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> Set<? extends Config<S>> getConfigs(S subject) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, C extends Config<S>> C addConfig(S subject, Class<C> configClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, C extends Config<S>> C applyConfig(S subject, Class<C> configClass, ObjectNode json) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, C extends Config<S>> void removeConfig(S subject, Class<C> configClass) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(NetworkConfigListener listener) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(NetworkConfigListener listener) {
|
||||
|
||||
}
|
||||
}
|
||||
@ -270,7 +270,11 @@ public class HostLocationProvider extends AbstractProvider implements HostProvid
|
||||
private void updateLocation(HostId hid, MacAddress mac,
|
||||
VlanId vlan, HostLocation hloc) {
|
||||
HostDescription desc = new DefaultHostDescription(mac, vlan, hloc);
|
||||
providerService.hostDetected(hid, desc);
|
||||
try {
|
||||
providerService.hostDetected(hid, desc);
|
||||
} catch (IllegalStateException e) {
|
||||
log.debug("Host {} suppressed", hid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -286,7 +290,11 @@ public class HostLocationProvider extends AbstractProvider implements HostProvid
|
||||
VlanId vlan, HostLocation hloc,
|
||||
IpAddress ip) {
|
||||
HostDescription desc = new DefaultHostDescription(mac, vlan, hloc, ip);
|
||||
providerService.hostDetected(hid, desc);
|
||||
try {
|
||||
providerService.hostDetected(hid, desc);
|
||||
} catch (IllegalStateException e) {
|
||||
log.debug("Host {} suppressed", hid);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -229,7 +229,12 @@ public class LinkDiscovery implements TimerTask {
|
||||
} else {
|
||||
ld = new DefaultLinkDescription(src, dst, Type.DIRECT);
|
||||
}
|
||||
linkProvider.linkDetected(ld);
|
||||
|
||||
try {
|
||||
linkProvider.linkDetected(ld);
|
||||
} catch (IllegalStateException e) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
38
tools/test/configs/override-basic.json
Normal file
38
tools/test/configs/override-basic.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"devices": {
|
||||
"of:0000000000000009": {
|
||||
"basic": {
|
||||
"allowed": true,
|
||||
"owner": "Luigi"
|
||||
}
|
||||
},
|
||||
"of:0000000000000008": {
|
||||
"basic": {
|
||||
"name": "NameChangeAgain",
|
||||
"allowed": true,
|
||||
"owner": "Mario"
|
||||
}
|
||||
},
|
||||
"of:0000000000000007": {
|
||||
"basic": {
|
||||
"allowed": true,
|
||||
"owner": "Peach",
|
||||
"latitude": "25"
|
||||
}
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"of:0000000000000006/2-of:0000000000000007/2": {
|
||||
"basic": {
|
||||
"allowed": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"hosts": {
|
||||
"00:00:00:00:00:03/-1": {
|
||||
"basic": {
|
||||
"allowed": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,13 +1,54 @@
|
||||
{
|
||||
"devices": {
|
||||
"of:001122334455667788" : {
|
||||
"basic" : {
|
||||
"allowed": false,
|
||||
"name": "Bad Device",
|
||||
"of:0000000000000009": {
|
||||
"basic": {
|
||||
"allowed": true,
|
||||
"owner": "Luigi"
|
||||
}
|
||||
},
|
||||
"of:0000000000000008": {
|
||||
"basic": {
|
||||
"name": "NameChange",
|
||||
"allowed": true,
|
||||
"owner": "Mario"
|
||||
}
|
||||
},
|
||||
"of:0000000000000007": {
|
||||
"basic": {
|
||||
"allowed": true,
|
||||
"owner": "Peach",
|
||||
"latitude": "25"
|
||||
}
|
||||
},
|
||||
"of:0000000000000003": {
|
||||
"basic": {
|
||||
"allowed": true,
|
||||
"owner": "Wario"
|
||||
}
|
||||
}
|
||||
},
|
||||
"hosts": {},
|
||||
"links": {}
|
||||
"links": {
|
||||
"of:0000000000000006/2-of:0000000000000007/2": {
|
||||
"basic": {
|
||||
"allowed": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"hosts": {
|
||||
"00:00:00:00:00:03/-1": {
|
||||
"basic": {
|
||||
"allowed": false
|
||||
}
|
||||
},
|
||||
"00:00:00:00:00:02/-1": {
|
||||
"basic": {
|
||||
"allowed": false
|
||||
}
|
||||
},
|
||||
"00:00:00:00:00:01/-1": {
|
||||
"basic": {
|
||||
"allowed": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -87,7 +87,7 @@ public class NetworkConfigWebResource extends AbstractWebResource {
|
||||
NetworkConfigService service = get(NetworkConfigService.class);
|
||||
ObjectNode root = mapper().createObjectNode();
|
||||
produceSubjectJson(service, root,
|
||||
service.getSubjectFactory(subjectKey).createSubject(subject));
|
||||
service.getSubjectFactory(subjectKey).createSubject(subject));
|
||||
return ok(root).build();
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ public class NetworkConfigWebResource extends AbstractWebResource {
|
||||
ObjectNode root = (ObjectNode) mapper().readTree(request);
|
||||
root.fieldNames()
|
||||
.forEachRemaining(sk -> consumeJson(service, (ObjectNode) root.path(sk),
|
||||
service.getSubjectFactory(sk)));
|
||||
service.getSubjectFactory(sk)));
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -183,8 +183,8 @@ public class NetworkConfigWebResource extends AbstractWebResource {
|
||||
NetworkConfigService service = get(NetworkConfigService.class);
|
||||
ObjectNode root = (ObjectNode) mapper().readTree(request);
|
||||
consumeSubjectJson(service, root,
|
||||
service.getSubjectFactory(subjectKey).createSubject(subject),
|
||||
subjectKey);
|
||||
service.getSubjectFactory(subjectKey).createSubject(subject),
|
||||
subjectKey);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -210,16 +210,16 @@ public class NetworkConfigWebResource extends AbstractWebResource {
|
||||
NetworkConfigService service = get(NetworkConfigService.class);
|
||||
ObjectNode root = (ObjectNode) mapper().readTree(request);
|
||||
service.applyConfig(service.getSubjectFactory(subjectKey).createSubject(subject),
|
||||
service.getConfigClass(subjectKey, configKey), root);
|
||||
service.getConfigClass(subjectKey, configKey), root);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
private void consumeJson(NetworkConfigService service, ObjectNode classNode,
|
||||
SubjectFactory subjectFactory) {
|
||||
classNode.fieldNames().forEachRemaining(s ->
|
||||
consumeSubjectJson(service, (ObjectNode) classNode.path(s),
|
||||
subjectFactory.createSubject(s),
|
||||
subjectFactory.subjectKey()));
|
||||
consumeSubjectJson(service, (ObjectNode) classNode.path(s),
|
||||
subjectFactory.createSubject(s),
|
||||
subjectFactory.subjectKey()));
|
||||
}
|
||||
|
||||
private void consumeSubjectJson(NetworkConfigService service,
|
||||
@ -227,7 +227,7 @@ public class NetworkConfigWebResource extends AbstractWebResource {
|
||||
String subjectKey) {
|
||||
subjectNode.fieldNames().forEachRemaining(c ->
|
||||
service.applyConfig(subject, service.getConfigClass(subjectKey, c),
|
||||
(ObjectNode) subjectNode.path(c)));
|
||||
(ObjectNode) subjectNode.path(c)));
|
||||
}
|
||||
|
||||
|
||||
@ -272,4 +272,46 @@ public class NetworkConfigWebResource extends AbstractWebResource {
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clears all network configurations.
|
||||
*
|
||||
* @return empty response
|
||||
*/
|
||||
@DELETE
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@SuppressWarnings("unchecked")
|
||||
public Response upload() {
|
||||
NetworkConfigService service = get(NetworkConfigService.class);
|
||||
service.getSubjectClasses().forEach(subjectClass -> {
|
||||
service.getSubjects(subjectClass).forEach(subject -> {
|
||||
service.getConfigs(subject).forEach(config -> {
|
||||
service.removeConfig(subject, config.getClass());
|
||||
});
|
||||
});
|
||||
});
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
// TODO: this one below doesn't work correctly
|
||||
/**
|
||||
* Clears network configuration for the specified subject class.
|
||||
*
|
||||
* @param subjectKey subject class key
|
||||
* @return empty response
|
||||
*/
|
||||
@DELETE
|
||||
@Path("{subjectKey}/")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@SuppressWarnings("unchecked")
|
||||
public Response upload(@PathParam("subjectKey") String subjectKey) {
|
||||
NetworkConfigService service = get(NetworkConfigService.class);
|
||||
service.getSubjects(service.getSubjectFactory(subjectKey).getClass()).forEach(subject -> {
|
||||
service.getConfigs(subject).forEach(config -> {
|
||||
service.removeConfig(subject, config.getClass());
|
||||
});
|
||||
});
|
||||
return Response.ok().build();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user