diff --git a/core/api/src/main/java/org/onosproject/net/device/DefaultDeviceDescription.java b/core/api/src/main/java/org/onosproject/net/device/DefaultDeviceDescription.java index d58e5b32ec..3a8c8c1f68 100644 --- a/core/api/src/main/java/org/onosproject/net/device/DefaultDeviceDescription.java +++ b/core/api/src/main/java/org/onosproject/net/device/DefaultDeviceDescription.java @@ -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; diff --git a/core/api/src/main/java/org/onosproject/net/link/LinkAdminService.java b/core/api/src/main/java/org/onosproject/net/link/LinkAdminService.java index 2e308b44e0..a0b5e1e2b9 100644 --- a/core/api/src/main/java/org/onosproject/net/link/LinkAdminService.java +++ b/core/api/src/main/java/org/onosproject/net/link/LinkAdminService.java @@ -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); } diff --git a/core/net/pom.xml b/core/net/pom.xml index c54be45c3b..e262d4acb2 100644 --- a/core/net/pom.xml +++ b/core/net/pom.xml @@ -58,12 +58,25 @@ test + + org.onosproject + onos-incubator-api + test + tests + ${project.version} + + org.easymock easymock test + + org.onosproject + onos-incubator-api + + org.apache.felix org.apache.felix.scr.annotations diff --git a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java index d71b79648d..17ff85c481 100644 --- a/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java +++ b/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java @@ -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 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 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); + } + } + } } diff --git a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java index 3335f5a87a..d36db84b56 100644 --- a/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java +++ b/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java @@ -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 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 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); + } + } + } } diff --git a/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java b/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java index 75134f3d38..e6fa300e53 100644 --- a/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java +++ b/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java @@ -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 links, boolean isSoftRemove) { + private void removeLinks(Set 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()); + } + } + } + } } diff --git a/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java b/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java index 4d8d2fc583..7597e7c5a4 100644 --- a/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java +++ b/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java @@ -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 { + } } diff --git a/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java b/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java index 77b199b4df..9e113f34ec 100644 --- a/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java +++ b/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java @@ -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 { + } } diff --git a/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java b/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java index f164fa8522..391b2fd721 100644 --- a/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java +++ b/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java @@ -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 { + } } diff --git a/incubator/api/src/test/java/org/onosproject/incubator/net/config/NetworkConfigServiceAdapter.java b/incubator/api/src/test/java/org/onosproject/incubator/net/config/NetworkConfigServiceAdapter.java new file mode 100644 index 0000000000..0e108c95ee --- /dev/null +++ b/incubator/api/src/test/java/org/onosproject/incubator/net/config/NetworkConfigServiceAdapter.java @@ -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 getSubjectClasses() { + return null; + } + + @Override + public SubjectFactory getSubjectFactory(String subjectKey) { + return null; + } + + @Override + public SubjectFactory getSubjectFactory(Class subjectClass) { + return null; + } + + @Override + public Class getConfigClass(String subjectKey, String configKey) { + return null; + } + + @Override + public Set getSubjects(Class subjectClass) { + return null; + } + + @Override + public > Set getSubjects(Class subjectClass, Class configClass) { + return null; + } + + @Override + public Set> getConfigs(S subject) { + return null; + } + + @Override + public > C getConfig(S subject, Class configClass) { + return null; + } + + @Override + public > C addConfig(S subject, Class configClass) { + return null; + } + + @Override + public > C applyConfig(S subject, Class configClass, ObjectNode json) { + return null; + } + + @Override + public > void removeConfig(S subject, Class configClass) { + + } + + @Override + public void addListener(NetworkConfigListener listener) { + + } + + @Override + public void removeListener(NetworkConfigListener listener) { + + } +} diff --git a/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java b/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java index a8c83837ac..10a845ffc1 100644 --- a/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java +++ b/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java @@ -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 diff --git a/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java b/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java index 6f3ffdc5ad..edf9a7bd49 100644 --- a/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java +++ b/providers/lldp/src/main/java/org/onosproject/provider/lldp/impl/LinkDiscovery.java @@ -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; diff --git a/tools/test/configs/override-basic.json b/tools/test/configs/override-basic.json new file mode 100644 index 0000000000..c1f23ce632 --- /dev/null +++ b/tools/test/configs/override-basic.json @@ -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 + } + } + } +} \ No newline at end of file diff --git a/tools/test/configs/sample-basic.json b/tools/test/configs/sample-basic.json index c3929dbe45..73cbd305a0 100644 --- a/tools/test/configs/sample-basic.json +++ b/tools/test/configs/sample-basic.json @@ -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 + } + } + } } \ No newline at end of file diff --git a/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java b/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java index 15c472d783..7837fca685 100644 --- a/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java +++ b/web/api/src/main/java/org/onosproject/rest/resources/NetworkConfigWebResource.java @@ -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(); + } }