From 6a07d2d622eaa06953f3353e39c080984076e8de Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Fri, 9 Oct 2015 18:32:44 -0700 Subject: Updated master to commit id 6ee8aa3e67ce89908a8c93aa9445c6f71a18f986 Change-Id: I94b055ee2f298daf71e2ec794fd0f2495bd8081f --- .../onosproject/cfg/ComponentConfigService.java | 11 + .../java/org/onosproject/net/AnnotationKeys.java | 16 +- .../org/onosproject/net/DefaultDisjointPath.java | 100 ++++ .../java/org/onosproject/net/DisjointPath.java | 49 ++ .../net/behaviour/ControllerConfig.java | 6 +- .../onosproject/net/behaviour/ControllerInfo.java | 100 +++- .../net/config/NetworkConfigService.java | 12 +- .../org/onosproject/net/config/SubjectFactory.java | 26 +- .../net/config/basics/BasicDeviceConfig.java | 20 + .../net/config/basics/SubjectFactories.java | 16 + .../net/flow/DefaultTableStatisticsEntry.java | 89 +++ .../net/flow/DefaultTrafficSelector.java | 22 +- .../net/flow/DefaultTrafficTreatment.java | 46 +- .../net/flow/DefaultTypedFlowEntry.java | 122 ++++ .../java/org/onosproject/net/flow/FlowRule.java | 37 -- .../net/flow/FlowRuleProviderService.java | 21 +- .../org/onosproject/net/flow/FlowRuleService.java | 7 + .../org/onosproject/net/flow/FlowRuleStore.java | 21 + .../onosproject/net/flow/TableStatisticsEntry.java | 59 ++ .../org/onosproject/net/flow/TrafficSelector.java | 24 - .../org/onosproject/net/flow/TrafficTreatment.java | 10 - .../onosproject/net/flow/TypedStoredFlowEntry.java | 65 +++ .../onosproject/net/flow/criteria/Criteria.java | 24 - .../net/flow/instructions/Instruction.java | 9 + .../net/flow/instructions/Instructions.java | 73 ++- .../onosproject/net/host/HostProviderService.java | 9 + .../java/org/onosproject/net/host/HostStore.java | 9 + .../org/onosproject/net/intent/FlowRuleIntent.java | 13 - .../java/org/onosproject/net/mcast/McastEvent.java | 118 ++++ .../org/onosproject/net/mcast/McastListener.java | 26 + .../java/org/onosproject/net/mcast/McastRoute.java | 117 ++++ .../net/mcast/MulticastRouteService.java | 84 +++ .../org/onosproject/net/mcast/package-info.java | 20 + .../onosproject/net/meter/DefaultMeterRequest.java | 5 +- .../java/org/onosproject/net/meter/MeterKey.java | 72 +++ .../org/onosproject/net/meter/MeterService.java | 4 +- .../java/org/onosproject/net/meter/MeterStore.java | 6 +- .../net/newresource/ResourceService.java | 9 + .../net/packet/PacketProcessorEntry.java | 58 ++ .../org/onosproject/net/packet/PacketService.java | 8 +- .../org/onosproject/net/packet/PacketStore.java | 6 +- .../net/packet/PacketStoreDelegate.java | 16 + .../net/resource/device/IntentSetMultimap.java | 47 ++ .../resource/link/BandwidthResourceRequest.java | 2 +- .../net/statistic/FlowStatisticService.java | 105 ++++ .../net/statistic/FlowStatisticStore.java | 65 +++ .../net/statistic/SummaryFlowEntryWithLoad.java | 143 +++++ .../net/statistic/TypedFlowEntryWithLoad.java | 143 +++++ .../net/topology/DefaultGraphDescription.java | 17 - .../org/onosproject/net/topology/PathService.java | 54 +- .../onosproject/net/topology/TopologyService.java | 63 +- .../onosproject/net/topology/TopologyStore.java | 55 ++ .../store/service/AsyncAtomicCounter.java | 17 + .../onosproject/store/service/AtomicCounter.java | 16 + .../store/service/MutexExecutionService.java | 34 ++ .../org/onosproject/store/service/MutexTask.java | 39 ++ .../onosproject/ui/table/cell/NumberFormatter.java | 50 ++ .../onosproject/cfg/ComponentConfigAdapter.java | 9 +- .../net/behaviour/ControllerInfoTest.java | 112 ++++ .../net/config/NetworkConfigServiceAdapter.java | 4 +- .../net/flow/DefaultTrafficSelectorTest.java | 24 - .../net/flow/FlowRuleServiceAdapter.java | 9 +- .../net/flow/criteria/CriteriaTest.java | 65 --- .../onosproject/net/intent/IntentTestsMocks.java | 19 +- .../net/packet/PacketServiceAdapter.java | 3 +- .../net/topology/DefaultGraphDescriptionTest.java | 4 +- .../net/topology/PathServiceAdapter.java | 62 ++ .../net/topology/TopologyServiceAdapter.java | 26 + .../store/service/TestAtomicCounter.java | 10 + .../org/onosproject/codec/impl/CodecManager.java | 3 + .../codec/impl/EncodeInstructionCodecHelper.java | 1 + .../codec/impl/TableStatisticsEntryCodec.java | 46 ++ .../org/onosproject/common/DefaultTopology.java | 140 ++++- .../onosproject/codec/impl/CriterionCodecTest.java | 15 - .../codec/impl/InstructionJsonMatcher.java | 2 + .../onosproject/common/DefaultTopologyTest.java | 2 +- .../store/trivial/SimpleFlowRuleStore.java | 23 + .../onosproject/store/trivial/SimpleHostStore.java | 5 + .../store/trivial/SimplePacketStore.java | 51 +- .../store/trivial/SimpleTopologyStore.java | 25 + framework/src/onos/core/net/pom.xml | 14 + .../cfg/impl/ComponentConfigLoader.java | 74 +++ .../cfg/impl/ComponentConfigManager.java | 24 + .../org/onosproject/core/impl/CoreManager.java | 17 +- .../net/config/impl/NetworkConfigManager.java | 12 +- .../net/device/impl/BasicDeviceOperator.java | 17 +- .../onosproject/net/device/impl/DeviceManager.java | 73 ++- .../net/device/impl/OpticalPortOperator.java | 19 +- .../onosproject/net/flow/impl/FlowRuleManager.java | 45 +- .../org/onosproject/net/host/impl/HostManager.java | 10 + .../org/onosproject/net/host/impl/HostMonitor.java | 1 + .../onosproject/net/intent/impl/IntentCleanup.java | 2 +- .../onosproject/net/intent/impl/IntentManager.java | 19 +- .../net/intent/impl/ObjectiveTracker.java | 26 +- .../compiler/OpticalCircuitIntentCompiler.java | 53 +- .../OpticalConnectivityIntentCompiler.java | 69 +-- .../impl/compiler/OpticalPathIntentCompiler.java | 4 - .../net/newresource/impl/ResourceManager.java | 8 + .../onosproject/net/packet/impl/PacketManager.java | 148 +++-- .../net/statistic/impl/FlowStatisticManager.java | 634 +++++++++++++++++++++ .../onosproject/net/topology/impl/PathManager.java | 103 ++++ .../net/topology/impl/TopologyManager.java | 43 +- .../cfg/impl/ComponentConfigLoaderTest.java | 126 ++++ .../onosproject/net/host/impl/HostMonitorTest.java | 214 ++++++- .../net/intent/impl/IntentManagerTest.java | 2 +- .../MultiPointToSinglePointIntentCompilerTest.java | 10 +- .../compiler/OpticalPathIntentCompilerTest.java | 12 - .../net/topology/impl/PathManagerTest.java | 6 +- .../net/topology/impl/TopologyManagerTest.java | 2 +- .../org/onosproject/cfg/impl/badComponent.json | 5 + .../org/onosproject/cfg/impl/badConfig.json | 5 + .../resources/org/onosproject/cfg/impl/basic.json | 5 + .../store/consistent/impl/Database.java | 4 +- .../store/consistent/impl/DatabaseManager.java | 5 +- .../store/consistent/impl/DatabaseProxy.java | 55 +- .../store/consistent/impl/DatabaseState.java | 18 +- .../consistent/impl/DefaultAsyncAtomicCounter.java | 21 +- .../consistent/impl/DefaultAtomicCounter.java | 10 + .../store/consistent/impl/DefaultDatabase.java | 24 +- .../consistent/impl/DefaultDatabaseState.java | 30 +- .../consistent/impl/MutexExecutionManager.java | 315 ++++++++++ .../store/consistent/impl/PartitionedDatabase.java | 89 +-- .../store/ecmap/EventuallyConsistentMapImpl.java | 20 +- .../flow/impl/NewDistributedFlowRuleStore.java | 64 +++ .../store/group/impl/DistributedGroupStore.java | 62 +- .../onosproject/store/host/impl/ECHostStore.java | 51 +- .../store/intent/impl/GossipIntentStore.java | 2 +- .../store/link/impl/GossipLinkStore.java | 4 +- .../store/packet/impl/DistributedPacketStore.java | 78 ++- .../resource/impl/ConsistentIntentSetMultimap.java | 111 ++++ .../resource/impl/ConsistentLinkResourceStore.java | 252 ++++---- .../impl/DistributedFlowStatisticStore.java | 289 ++++++++++ .../topology/impl/DistributedTopologyStore.java | 26 +- .../store/host/impl/ECHostStoreTest.java | 95 +++ .../store/serializers/KryoNamespaces.java | 12 +- 135 files changed, 5586 insertions(+), 928 deletions(-) create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultDisjointPath.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/DisjointPath.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTableStatisticsEntry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTypedFlowEntry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TableStatisticsEntry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TypedStoredFlowEntry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastRoute.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/MulticastRouteService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterKey.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProcessorEntry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/IntentSetMultimap.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/SummaryFlowEntryWithLoad.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/TypedFlowEntryWithLoad.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexExecutionService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexTask.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/NumberFormatter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/behaviour/ControllerInfoTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/PathServiceAdapter.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TableStatisticsEntryCodec.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigLoader.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/FlowStatisticManager.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ComponentConfigLoaderTest.java create mode 100644 framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badComponent.json create mode 100644 framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badConfig.json create mode 100644 framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/basic.json create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/MutexExecutionManager.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentIntentSetMultimap.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/statistic/impl/DistributedFlowStatisticStore.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/host/impl/ECHostStoreTest.java (limited to 'framework/src/onos/core') diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java index a311002f..408a8933 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java @@ -62,6 +62,16 @@ public interface ComponentConfigService { */ void setProperty(String componentName, String name, String value); + /** + * Presets the value of the specified configuration property, regardless + * of the component's state. + * + * @param componentName component name + * @param name property name + * @param value new property value + */ + void preSetProperty(String componentName, String name, String value); + /** * Clears the value of the specified configuration property thus making * the property take on its default value. @@ -72,3 +82,4 @@ public interface ComponentConfigService { void unsetProperty(String componentName, String name); } + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java index 4949bc40..8c5fb790 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java @@ -25,8 +25,10 @@ package org.onosproject.net; */ public final class AnnotationKeys { + // Prohibit instantiation - private AnnotationKeys() {} + private AnnotationKeys() { + } /** * Annotation key for instance name. @@ -124,13 +126,23 @@ public final class AnnotationKeys { */ public static final String OWNER = "owner"; + /** + * Annotation key for the channel id. + */ + public static final String CHANNEL_ID = "channelId"; + + /** + * Annotation key for the management address. + */ + public static final String MANAGEMENT_ADDRESS = "managementAddress"; + /** * Returns the value annotated object for the specified annotation key. * The annotated value is expected to be String that can be parsed as double. * If parsing fails, the returned value will be 1.0. * * @param annotated annotated object whose annotated value is obtained - * @param key key of annotation + * @param key key of annotation * @return double value of annotated object for the specified key */ public static double getAnnotatedValue(Annotated annotated, String key) { diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultDisjointPath.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultDisjointPath.java new file mode 100644 index 00000000..4895964f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultDisjointPath.java @@ -0,0 +1,100 @@ +/* + * 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.net; + +import org.onosproject.net.provider.ProviderId; + +import java.util.List; +import java.util.Objects; +import static com.google.common.collect.ImmutableSet.of; + +/** + * Default implementation of a network disjoint path pair. + */ +public class DefaultDisjointPath extends DefaultPath implements DisjointPath { + + private final DefaultPath path1; + private final DefaultPath path2; + + boolean usingPath1 = true; + + /** + * Creates a disjoint path pair from two default paths. + * + * @param providerId provider identity + * @param path1 primary path + * @param path2 backup path + */ + public DefaultDisjointPath(ProviderId providerId, DefaultPath path1, DefaultPath path2) { + super(providerId, path1.links(), path1.cost() + path2.cost()); + this.path1 = path1; + this.path2 = path2; + } + + @Override + public List links() { + if (usingPath1) { + return path1.links(); + } else { + return path2.links(); + } + } + + @Override + public double cost() { + if (usingPath1) { + return path1.cost(); + } + return path2.cost(); + } + + @Override + public Path primary() { + return path1; + } + + @Override + public Path backup() { + return path2; + } + + @Override + public int hashCode() { + return Objects.hash(of(path1, path2), src(), dst()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultDisjointPath) { + final DefaultDisjointPath other = (DefaultDisjointPath) obj; + return Objects.equals(this.path1, other.path1) && Objects.equals(this.path2, other.path2); + } + return false; + } + + @Override + public boolean useBackup() { + if (path2 == null || path2.links() == null) { + return false; + } + usingPath1 = !usingPath1; + return true; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/DisjointPath.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DisjointPath.java new file mode 100644 index 00000000..3d54cbfc --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DisjointPath.java @@ -0,0 +1,49 @@ +/* + * 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.net; + + +/** + * Representation of a contiguous directed path in a network. Path comprises + * of a sequence of links, where adjacent links must share the same device, + * meaning that destination of the source of one link must coincide with the + * destination of the previous link. + */ +public interface DisjointPath extends Path { + + /** + * Uses backup path. + * + * @return boolean corresponding to whether request to use + * backup was successful. + */ + boolean useBackup(); + + /** + * Gets primary path. + * + * @return primary path + */ + Path primary(); + + /** + * Gets secondary path. + * + * @return secondary path + */ + Path backup(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java index bb8a788b..cd7cb977 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java @@ -15,23 +15,27 @@ */ package org.onosproject.net.behaviour; +import org.onosproject.net.driver.HandlerBehaviour; + import java.util.List; /** * Device behaviour to obtain and set controllers at the device. */ -public interface ControllerConfig { +public interface ControllerConfig extends HandlerBehaviour { //TODO: add other controller parameters as needed. /** * Obtain the list of controller which are currently configured. + * * @return a list for controller descriptions */ List getControllers(); /** * Set a list of controllers on a device. + * * @param controllers a list of controller descriptions */ void setControllers(List controllers); diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java index 9ff808a9..ded3b3ae 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java @@ -15,24 +15,112 @@ */ package org.onosproject.net.behaviour; +import com.google.common.base.Preconditions; import org.onlab.packet.IpAddress; +import java.util.Objects; + /** * Represents information for a device to connect to a controller. */ public class ControllerInfo { - public final IpAddress ip; - public final int tcpPort; + private IpAddress ip = IpAddress.valueOf("0.0.0.0"); + private int port = 6653; + private String type = "error"; /** * Information for contacting the controller. * - * @param ip the ip address - * @param tcpPort the tcp port + * @param ip the ip address + * @param port the tcp port */ - public ControllerInfo(IpAddress ip, int tcpPort) { + public ControllerInfo(IpAddress ip, int port, String type) { this.ip = ip; - this.tcpPort = tcpPort; + this.port = port; + this.type = type; + } + + /** + * Information for contacting the controller, if some information + * is not contained in the target string because it's optional + * it's leaved as in the field declaration (default values). + * + * @param target column returned from ovsdb query + */ + public ControllerInfo(String target) { + String[] data = target.split(":"); + this.type = data[0]; + Preconditions.checkArgument(!data[0].contains("unix"), + "Unable to create controller info " + + "from {} because it's based " + + "on unix sockets", target); + if (data[0].startsWith("p")) { + if (data.length >= 2) { + this.port = Integer.parseInt(data[1]); + } + if (data.length == 3) { + this.ip = IpAddress.valueOf(data[2]); + } + } else { + this.ip = IpAddress.valueOf(data[1]); + if (data.length == 3) { + this.port = Integer.parseInt(data[2]); + } + } + } + + /** + * Exposes the ip address of the controller. + * + * @return IpAddress ip address + */ + public IpAddress ip() { + return ip; + } + + /** + * Exposes the tcp port of the controller. + * + * @return int tcp port + */ + public int port() { + return port; + } + + /** + * Exposes the type of the controller connection. + * + * @return String type + */ + public String type() { + return type; + } + + public String target() { + if (type.startsWith("p")) { + return type + ":" + port + ":" + ip; + } else { + return type + ":" + ip + ":" + port; + } + } + + + @Override + public int hashCode() { + return Objects.hash(ip, port, type); + } + + @Override + public boolean equals(Object toBeCompared) { + if (toBeCompared instanceof ControllerInfo) { + ControllerInfo controllerInfo = (ControllerInfo) toBeCompared; + if (controllerInfo.type().equals(this.type) + && controllerInfo.ip().equals(this.ip()) + && controllerInfo.port() == this.port) { + return true; + } + } + return false; } } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java index c1eed980..8eb69a45 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java @@ -41,27 +41,27 @@ public interface NetworkConfigService /** * Returns the subject factory with the specified key. * - * @param subjectKey subject class key + * @param subjectClassKey subject class key * @return subject class */ - SubjectFactory getSubjectFactory(String subjectKey); + SubjectFactory getSubjectFactory(String subjectClassKey); /** * Returns the subject factory for the specified class. * * @param subjectClass subject class - * @return subject class key + * @return subject class factory */ SubjectFactory getSubjectFactory(Class subjectClass); /** * Returns the configuration class with the specified key. * - * @param subjectKey subject class key - * @param configKey subject class name + * @param subjectClassKey subject class key + * @param configKey subject class name * @return subject class */ - Class getConfigClass(String subjectKey, String configKey); + Class getConfigClass(String subjectClassKey, String configKey); /** * Returns the set of subjects for which some configuration is available. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/SubjectFactory.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/SubjectFactory.java index cd2db344..f992d727 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/SubjectFactory.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/SubjectFactory.java @@ -28,7 +28,7 @@ import com.google.common.annotations.Beta; public abstract class SubjectFactory { private final Class subjectClass; - private final String subjectKey; + private final String subjectClassKey; /** * Creates a new configuration factory for the specified class of subjects @@ -36,12 +36,12 @@ public abstract class SubjectFactory { * subject and configuration class keys are used merely as keys for use in * composite JSON trees. * - * @param subjectClass subject class - * @param subjectKey subject class key + * @param subjectClass subject class + * @param subjectClassKey subject class key */ - protected SubjectFactory(Class subjectClass, String subjectKey) { + protected SubjectFactory(Class subjectClass, String subjectClassKey) { this.subjectClass = subjectClass; - this.subjectKey = subjectKey; + this.subjectClassKey = subjectClassKey; } /** @@ -60,8 +60,20 @@ public abstract class SubjectFactory { * * @return configuration key */ - public String subjectKey() { - return subjectKey; + public String subjectClassKey() { + return subjectClassKey; + } + + /** + * Returns the unique key of the specified configuration subject. + * This is primarily aimed for use in composite JSON trees in external + * representations and has no bearing on the internal behaviours. + * + * @param subject specific subject + * @return subject key + */ + public String subjectKey(S subject) { + return subject.toString(); } /** diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicDeviceConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicDeviceConfig.java index fd8bfa3e..afde9a9e 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicDeviceConfig.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicDeviceConfig.java @@ -25,6 +25,7 @@ public class BasicDeviceConfig extends BasicElementConfig { public static final String TYPE = "type"; public static final String DRIVER = "driver"; + public static final String MANAGEMENT_ADDRESS = "managementAddress"; /** * Returns the device type. @@ -64,6 +65,25 @@ public class BasicDeviceConfig extends BasicElementConfig { return (BasicElementConfig) setOrClear(DRIVER, driverName); } + /** + * Returns the device management ip (ip:port). + * + * @return device management address (ip:port) or null if not set + */ + public String managementAddress() { + return get(MANAGEMENT_ADDRESS, null); + } + + /** + * Sets the driver name. + * + * @param managementAddress new device management address (ip:port); null to clear + * @return self + */ + public BasicElementConfig managementAddress(String managementAddress) { + return (BasicElementConfig) setOrClear(MANAGEMENT_ADDRESS, managementAddress); + } + // TODO: device port meta-data to be configured via BasicPortsConfig // TODO: device credentials/keys diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/SubjectFactories.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/SubjectFactories.java index 884f2e20..311566b3 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/SubjectFactories.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/SubjectFactories.java @@ -43,6 +43,10 @@ public final class SubjectFactories { public ApplicationId createSubject(String key) { return coreService.registerApplication(key); } + @Override + public String subjectKey(ApplicationId subject) { + return subject.name(); + } }; public static final SubjectFactory DEVICE_SUBJECT_FACTORY = @@ -59,6 +63,10 @@ public final class SubjectFactories { public ConnectPoint createSubject(String key) { return ConnectPoint.deviceConnectPoint(key); } + @Override + public String subjectKey(ConnectPoint subject) { + return key(subject); + } }; public static final SubjectFactory HOST_SUBJECT_FACTORY = @@ -78,6 +86,10 @@ public final class SubjectFactories { return LinkKey.linkKey(ConnectPoint.deviceConnectPoint(cps[0]), ConnectPoint.deviceConnectPoint(cps[1])); } + @Override + public String subjectKey(LinkKey subject) { + return key(subject.src()) + "-" + key(subject.dst()); + } }; /** @@ -90,4 +102,8 @@ public final class SubjectFactories { coreService = service; } + private static String key(ConnectPoint subject) { + return subject.deviceId() + "/" + subject.port(); + } + } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTableStatisticsEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTableStatisticsEntry.java new file mode 100644 index 00000000..929b285d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTableStatisticsEntry.java @@ -0,0 +1,89 @@ +/* + * 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.net.flow; + +import org.onosproject.net.DeviceId; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default implementation of table statistics entry interface. + */ +public final class DefaultTableStatisticsEntry implements TableStatisticsEntry { + + private final DeviceId deviceId; + private final int tableId; + private final long activeFlowEntries; + private final long packetsLookedupCount; + private final long packetsMatchedCount; + + /** + * Default table statistics constructor. + * + * @param deviceId device identifier + * @param tableId table identifier + * @param activeFlowEntries number of active flow entries in the table + * @param packetsLookedupCount number of packets looked up in table + * @param packetsMatchedCount number of packets that hit table + */ + public DefaultTableStatisticsEntry(DeviceId deviceId, + int tableId, + long activeFlowEntries, + long packetsLookedupCount, + long packetsMatchedCount) { + this.deviceId = checkNotNull(deviceId); + this.tableId = tableId; + this.activeFlowEntries = activeFlowEntries; + this.packetsLookedupCount = packetsLookedupCount; + this.packetsMatchedCount = packetsMatchedCount; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("device: " + deviceId + ", "); + + sb.append("tableId: " + this.tableId + ", "); + sb.append("activeEntries: " + this.activeFlowEntries + ", "); + sb.append("packetsLookedUp: " + this.packetsLookedupCount + ", "); + sb.append("packetsMatched: " + this.packetsMatchedCount); + + return sb.toString(); + } + + @Override + public int tableId() { + return tableId; + } + + @Override + public long activeFlowEntries() { + return activeFlowEntries; + } + + @Override + public long packetsLookedup() { + return packetsLookedupCount; + } + + @Override + public long packetsMatched() { + return packetsMatchedCount; + } + + @Override + public DeviceId deviceId() { + return deviceId; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java index f88c6bc3..4416456c 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java @@ -23,22 +23,26 @@ import org.onlab.packet.MacAddress; import org.onlab.packet.MplsLabel; import org.onlab.packet.TpPort; import org.onlab.packet.VlanId; -import org.onosproject.net.IndexedLambda; import org.onosproject.net.PortNumber; import org.onosproject.net.flow.criteria.Criteria; import org.onosproject.net.flow.criteria.Criterion; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.TreeSet; /** * Default traffic selector implementation. */ public final class DefaultTrafficSelector implements TrafficSelector { + private static final Comparator TYPE_COMPARATOR = + (c1, c2) -> c1.type().compareTo(c2.type()); + private final Set criteria; private static final TrafficSelector EMPTY @@ -50,7 +54,9 @@ public final class DefaultTrafficSelector implements TrafficSelector { * @param criteria criteria */ private DefaultTrafficSelector(Set criteria) { - this.criteria = ImmutableSet.copyOf(criteria); + TreeSet elements = new TreeSet<>(TYPE_COMPARATOR); + elements.addAll(criteria); + this.criteria = ImmutableSet.copyOf(elements); } @Override @@ -345,18 +351,6 @@ public final class DefaultTrafficSelector implements TrafficSelector { return add(Criteria.matchIPv6ExthdrFlags(exthdrFlags)); } - @Deprecated - @Override - public Builder matchLambda(short lambda) { - return add(Criteria.matchLambda(new IndexedLambda(lambda))); - } - - @Deprecated - @Override - public Builder matchOpticalSignalType(short signalType) { - return add(Criteria.matchOpticalSignalType(signalType)); - } - @Override public TrafficSelector build() { return new DefaultTrafficSelector(ImmutableSet.copyOf(selector.values())); diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java index 5d18a9ad..a628725c 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java @@ -31,7 +31,6 @@ import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.meter.MeterId; -import java.util.Collections; import java.util.List; import java.util.Objects; @@ -51,7 +50,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { private final boolean hasClear; private static final DefaultTrafficTreatment EMPTY - = new DefaultTrafficTreatment(Collections.emptyList()); + = new DefaultTrafficTreatment(ImmutableList.of(Instructions.createNoAction())); private final Instructions.MeterInstruction meter; /** @@ -212,8 +211,6 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { List current = immediate; - - // Creates a new builder private Builder() { } @@ -224,7 +221,10 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { treatment.deferred().forEach(i -> add(i)); immediate(); - treatment.immediate().forEach(i -> add(i)); + treatment.immediate().stream() + // NOACTION will get re-added if there are no other actions + .filter(i -> i.type() != Instruction.Type.NOACTION) + .forEach(i -> add(i)); clear = treatment.clearedDeferred(); } @@ -234,6 +234,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { switch (instruction.type()) { case DROP: + case NOACTION: case OUTPUT: case GROUP: case L0MODIFICATION: @@ -250,6 +251,7 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { break; case METER: meter = (Instructions.MeterInstruction) instruction; + break; default: throw new IllegalArgumentException("Unknown instruction type: " + instruction.type()); @@ -258,9 +260,23 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { return this; } + /** + * Add a NOACTION when DROP instruction is explicitly specified. + * + * @return the traffic treatment builder + */ @Override public Builder drop() { - return add(Instructions.createDrop()); + return add(Instructions.createNoAction()); + } + + /** + * Add a NOACTION when no instruction is specified. + * + * @return the traffic treatment builder + */ + private Builder noAction() { + return add(Instructions.createNoAction()); } @Override @@ -379,11 +395,6 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { return add(Instructions.pushVlan()); } - @Override - public Builder transition(FlowRule.Type type) { - return add(Instructions.transition(type.ordinal())); - } - @Override public Builder transition(Integer tableId) { return add(Instructions.transition(tableId)); @@ -463,14 +474,11 @@ public final class DefaultTrafficTreatment implements TrafficTreatment { @Override public TrafficTreatment build() { - //Don't add DROP instruction by default when instruction - //set is empty. This will be handled in DefaultSingleTablePipeline - //driver. - - //if (deferred.size() == 0 && immediate.size() == 0 - // && table == null && !clear) { - // drop(); - //} + if (deferred.size() == 0 && immediate.size() == 0 + && table == null && !clear) { + immediate(); + noAction(); + } return new DefaultTrafficTreatment(deferred, immediate, table, clear, meta, meter); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTypedFlowEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTypedFlowEntry.java new file mode 100644 index 00000000..afceb14e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTypedFlowEntry.java @@ -0,0 +1,122 @@ +/* + * 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.net.flow; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Default flow entry class with FlowLiveType value, IMMEDIATE_FLOW, SHORT_FLOW, MID_FLOW, LONG_FLOW. + */ +public class DefaultTypedFlowEntry extends DefaultFlowEntry + implements TypedStoredFlowEntry { + private FlowLiveType liveType; + + /** + * Creates a typed flow entry from flow rule and its statistics, with default flow live type(IMMEDIATE_FLOW). + * + * @param rule the flow rule + * @param state the flow state + * @param life the flow duration since creation + * @param packets the flow packets count + * @param bytes the flow bytes count + * + */ + public DefaultTypedFlowEntry(FlowRule rule, FlowEntryState state, + long life, long packets, long bytes) { + super(rule, state, life, packets, bytes); + this.liveType = FlowLiveType.IMMEDIATE_FLOW; + } + + /** + * Creates a typed flow entry from flow rule, with default flow live type(IMMEDIATE_FLOW). + * + * @param rule the flow rule + * + */ + public DefaultTypedFlowEntry(FlowRule rule) { + super(rule); + this.liveType = FlowLiveType.IMMEDIATE_FLOW; + } + + /** + * Creates a typed flow entry from flow entry, with default flow live type(IMMEDIATE_FLOW). + * + * @param fe the flow entry + * + */ + public DefaultTypedFlowEntry(FlowEntry fe) { + super(fe, fe.state(), fe.life(), fe.packets(), fe.bytes()); + this.liveType = FlowLiveType.IMMEDIATE_FLOW; + } + + /** + * Creates a typed flow entry from flow rule and flow live type. + * + * @param rule the flow rule + * @param liveType the flow live type + * + */ + public DefaultTypedFlowEntry(FlowRule rule, FlowLiveType liveType) { + super(rule); + this.liveType = liveType; + } + + /** + * Creates a typed flow entry from flow entry and flow live type. + * + * @param fe the flow rule + * @param liveType the flow live type + * + */ + public DefaultTypedFlowEntry(FlowEntry fe, FlowLiveType liveType) { + super(fe, fe.state(), fe.life(), fe.packets(), fe.bytes()); + this.liveType = liveType; + } + + /** + * Creates a typed flow entry from flow rule, error code and flow live type. + * + * @param rule the flow rule + * @param errType the flow error type + * @param errCode the flow error code + * @param liveType the flow live type + * + */ + public DefaultTypedFlowEntry(FlowRule rule, int errType, int errCode, FlowLiveType liveType) { + super(rule, errType, errCode); + this.liveType = liveType; + } + + @Override + public FlowLiveType flowLiveType() { + return this.liveType; + } + + @Override + public void setFlowLiveType(FlowLiveType liveType) { + this.liveType = liveType; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("entry", super.toString()) + .add("type", liveType) + .toString(); + } +} + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java index a487cbc4..35d45fbd 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java @@ -28,43 +28,6 @@ public interface FlowRule { int MAX_TIMEOUT = 60; int MIN_PRIORITY = 0; - /** - * The FlowRule type is used to determine in which table the flow rule needs - * to be put for multi-table support switch. For single table switch, - * Default is used. - * - * @deprecated in Cardinal Release - */ - @Deprecated - enum Type { - /* - * Default type - used in flow rule for single table switch NOTE: this - * setting should not be used as Table 0 in a multi-table pipeline - */ - DEFAULT, - /* Used in flow entry for IP table */ - IP, - /* Used in flow entry for MPLS table */ - MPLS, - /* Used in flow entry for ACL table */ - ACL, - - /* VLAN-to-MPLS table */ - VLAN_MPLS, - - /* VLAN table */ - VLAN, - - /* Ethtype table */ - ETHER, - - /* Class of Service table */ - COS, - - /* Table 0 in a multi-table pipeline */ - FIRST, - } - /** * Returns the ID of this flow. * diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderService.java index 8a36a921..aefa96b4 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderService.java @@ -15,6 +15,8 @@ */ package org.onosproject.net.flow; +import java.util.List; + import org.onosproject.net.DeviceId; import org.onosproject.net.provider.ProviderService; @@ -40,6 +42,24 @@ public interface FlowRuleProviderService extends ProviderService flowEntries); + /** + * Pushes the collection of flow entries currently applied on the given + * device without flowMissing process. + * + * @param deviceId device identifier + * @param flowEntries collection of flow rules + */ + void pushFlowMetricsWithoutFlowMissing(DeviceId deviceId, Iterable flowEntries); + + /** + * Pushes the collection of table statistics entries currently extracted + * from the given device. + * + * @param deviceId device identifier + * @param tableStatsEntries collection of flow table statistics entries + */ + void pushTableStatistics(DeviceId deviceId, List tableStatsEntries); + /** * Indicates to the core that the requested batch operation has * been completed. @@ -48,5 +68,4 @@ public interface FlowRuleProviderService extends ProviderService getFlowTableStatistics(DeviceId deviceId); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java index cece9893..d81c73c9 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java @@ -15,6 +15,8 @@ */ package org.onosproject.net.flow; +import java.util.List; + import org.onosproject.net.DeviceId; import org.onosproject.store.Store; @@ -93,4 +95,23 @@ public interface FlowRuleStore extends Store tableStats); + + /** + * Returns the flow table statistics associated with a device. + * + * @param deviceId the device ID + * @return the flow table statistics + */ + Iterable getTableStatistics(DeviceId deviceId); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TableStatisticsEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TableStatisticsEntry.java new file mode 100644 index 00000000..563f31ce --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TableStatisticsEntry.java @@ -0,0 +1,59 @@ +/* + * 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.net.flow; + +import org.onosproject.net.DeviceId; + +/** + * Interface for flow table statistics of a device. + */ +public interface TableStatisticsEntry { + + /** + * Returns the device Id. + * + * @return device id + */ + DeviceId deviceId(); + + /** + * Returns the table number. + * + * @return table number + */ + int tableId(); + + /** + * Returns the number of active flow entries in this table. + * + * @return the number of active flow entries + */ + long activeFlowEntries(); + + /** + * Returns the number of packets looked up in the table. + * + * @return the number of packets looked up in the table + */ + long packetsLookedup(); + + /** + * Returns the number of packets that successfully matched in the table. + * + * @return the number of packets that successfully matched in the table + */ + long packetsMatched(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java index 534f6b9e..1286ffc1 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java @@ -385,30 +385,6 @@ public interface TrafficSelector { */ Builder matchIPv6ExthdrFlags(short exthdrFlags); - /** - * Matches an optical signal ID or lambda. - * - * @param lambda lambda - * @return a selection builder - * @deprecated in Cardinal Release. - * Use {@link #add(Criterion)} with an instance created - * by {@link org.onosproject.net.flow.criteria.Criteria#matchLambda(org.onosproject.net.Lambda)}. - */ - @Deprecated - Builder matchLambda(short lambda); - - /** - * Matches an optical Signal Type. - * - * @param signalType signalType - * @return a selection builder - * @deprecated in Cardinal Release. - * Use {@link #add(Criterion)}} with an instance created - * by {@link org.onosproject.net.flow.criteria.Criteria#matchOchSignalType(org.onosproject.net.OchSignalType)}. - */ - @Deprecated - Builder matchOpticalSignalType(short signalType); - /** * Builds an immutable traffic selector. * diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java index 1ce669c2..33753afa 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java @@ -268,16 +268,6 @@ public interface TrafficTreatment { */ Builder meter(MeterId meterId); - /** - * Sets the next table type to transition to. - * - * @param type the table type - * @return a treatement builder - * @deprecated in Cardinal Release - */ - @Deprecated - Builder transition(FlowRule.Type type); - /** * Sets the next table id to transition to. * diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TypedStoredFlowEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TypedStoredFlowEntry.java new file mode 100644 index 00000000..a93dc071 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TypedStoredFlowEntry.java @@ -0,0 +1,65 @@ +/* + * 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.net.flow; + +/** + * Represents a flow live type for a given flow entry. + */ +public interface TypedStoredFlowEntry extends StoredFlowEntry { + enum FlowLiveType { + /** + * Indicates that this rule has been submitted for addition immediately. + * Not necessarily collecting flow stats. + */ + IMMEDIATE_FLOW, + + /** + * Indicates that this rule has been submitted for a short time. + * Necessarily collecting flow stats every calAndPollInterval. + */ + SHORT_FLOW, + + /** + * Indicates that this rule has been submitted for a mid time. + * Necessarily collecting flow stats every midPollInterval. + */ + MID_FLOW, + + /** + * Indicates that this rule has been submitted for a long time. + * Necessarily collecting flow stats every longPollInterval. + */ + LONG_FLOW, + + /** + * Indicates that this rule has been submitted for UNKNOWN or ERROR. + * Not necessarily collecting flow stats. + */ + UNKNOWN_FLOW + } + + /** + * Gets the flow live type for this entry. + */ + FlowLiveType flowLiveType(); + + /** + * Sets the new flow live type for this entry. + * @param liveType new flow live type. + */ + void setFlowLiveType(FlowLiveType liveType); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java index 0252cfbc..7e1d43a5 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java @@ -460,18 +460,6 @@ public final class Criteria { return new IPv6ExthdrFlagsCriterion(exthdrFlags); } - /** - * Creates a match on lambda field using the specified value. - * - * @param lambda lambda to match on (16 bits unsigned integer) - * @return match criterion - * @deprecated in Cardinal Release. Use {@link #matchLambda(Lambda)} instead. - */ - @Deprecated - public static Criterion matchLambda(int lambda) { - return new LambdaCriterion(lambda, Type.OCH_SIGID); - } - /** * Creates a match on lambda using the specified value. * @@ -488,18 +476,6 @@ public final class Criteria { } } - /** - * Creates a match on optical signal type using the specified value. - * - * @param sigType optical signal type (8 bits unsigned integer) - * @return match criterion - * @deprecated in Cardinal Release - */ - @Deprecated - public static Criterion matchOpticalSignalType(short sigType) { - return new OpticalSignalTypeCriterion(sigType, Type.OCH_SIGTYPE); - } - /** * Create a match on OCh (Optical Channel) signal type. * diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java index 6f2cac6b..d01ea298 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java @@ -27,8 +27,17 @@ public interface Instruction { /** * Signifies that the traffic should be dropped. */ + @Deprecated DROP, + /** + * Signifies that the traffic requires no action. + * + * In OF10, the behavior of NOACTION is DROP. + * In OF13, the behavior depends on current Action Set. + */ + NOACTION, + /** * Signifies that the traffic should be output to a port. */ diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java index c5358a29..c9f10685 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java @@ -68,10 +68,20 @@ public final class Instructions { * * @return drop instruction */ + @Deprecated public static DropInstruction createDrop() { return new DropInstruction(); } + /** + * Creates a no action instruction. + * + * @return no action instruction + */ + public static NoActionInstruction createNoAction() { + return new NoActionInstruction(); + } + /** * Creates a group instruction. * @@ -88,19 +98,6 @@ public final class Instructions { return new MeterInstruction(meterId); } - /** - * Creates a l0 modification. - * - * @param lambda the lambda to modify to - * @return a l0 modification - * @deprecated in Cardinal Release. Use {@link #modL0Lambda(Lambda)} instead. - */ - @Deprecated - public static L0ModificationInstruction modL0Lambda(short lambda) { - checkNotNull(lambda, "L0 lambda cannot be null"); - return new ModLambdaInstruction(L0SubType.LAMBDA, lambda); - } - /** * Creates an L0 modification with the specified OCh signal. * @@ -298,21 +295,6 @@ public final class Instructions { EthType.EtherType.MPLS_UNICAST.ethType()); } - /** - * Creates a pop MPLS header instruction with a particular ethertype. - * - * @param etherType Ethernet type to set - * @return a L2 modification. - * @deprecated in Cardinal Release - */ - @Deprecated - public static Instruction popMpls(int etherType) { - checkNotNull(etherType, "Ethernet type cannot be null"); - return new L2ModificationInstruction.PushHeaderInstructions( - L2ModificationInstruction.L2SubType.MPLS_POP, new EthType(etherType)); - } - - /** * Creates a pop MPLS header instruction with a particular ethertype. * @@ -478,6 +460,7 @@ public final class Instructions { /** * Drop instruction. */ + @Deprecated public static final class DropInstruction implements Instruction { private DropInstruction() {} @@ -509,6 +492,40 @@ public final class Instructions { } } + /** + * No Action instruction. + */ + public static final class NoActionInstruction implements Instruction { + + private NoActionInstruction() {} + + @Override + public Type type() { + return Type.NOACTION; + } + + @Override + public String toString() { + return toStringHelper(type().toString()).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof NoActionInstruction) { + return true; + } + return false; + } + } + /** * Output Instruction. */ diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderService.java index f7b7c499..068663bd 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderService.java @@ -15,6 +15,7 @@ */ package org.onosproject.net.host; +import org.onlab.packet.IpAddress; import org.onosproject.net.HostId; import org.onosproject.net.provider.ProviderService; @@ -29,6 +30,7 @@ public interface HostProviderService extends ProviderService { * * @param hostId id of the host that been detected * @param hostDescription description of host and its location + * @deprecated in Drake release */ @Deprecated default void hostDetected(HostId hostId, HostDescription hostDescription) { @@ -52,4 +54,11 @@ public interface HostProviderService extends ProviderService { */ void hostVanished(HostId hostId); + /** + * Notifies the core when a host is no longer detected on a network. + * + * @param hostId id of the host that vanished + */ + void removeIpFromHost(HostId hostId, IpAddress ipAddress); + } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStore.java index 5894fe92..918ced45 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStore.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStore.java @@ -54,6 +54,15 @@ public interface HostStore extends Store { */ HostEvent removeHost(HostId hostId); + /** + * Removes the specified ip from the host entry. + * + * @param hostId host identification + * @param ipAddress ipAddress to be removed + * @return remove event or null if host was not found + */ + HostEvent removeIp(HostId hostId, IpAddress ipAddress); + /** * Returns the number of hosts in the store. * diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java index 0646a003..2a2d7c78 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java @@ -23,7 +23,6 @@ import org.onosproject.net.NetworkResource; import org.onosproject.net.flow.FlowRule; import java.util.Collection; -import java.util.Collections; import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; @@ -37,18 +36,6 @@ public class FlowRuleIntent extends Intent { private final Collection flowRules; - /** - * Creates an flow rule intent with the specified flow rules to be set. - * - * @param appId application id - * @param flowRules flow rules to be set. - * @deprecated in Cardinal Release - */ - @Deprecated - public FlowRuleIntent(ApplicationId appId, List flowRules) { - this(appId, null, flowRules, Collections.emptyList()); - } - /** * Creates a flow rule intent with the specified flow rules and resources. * diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastEvent.java new file mode 100644 index 00000000..979194c3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastEvent.java @@ -0,0 +1,118 @@ +/* + * 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.net.mcast; + +import com.google.common.annotations.Beta; +import org.onosproject.event.AbstractEvent; +import org.onosproject.net.ConnectPoint; + +import java.util.Optional; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * An entity representing a multicast event. Event either add or remove + * sinks or sources. + */ +@Beta +public class McastEvent extends AbstractEvent { + + private final Optional sink; + private final Optional source; + + public enum Type { + /** + * A new mcast route has been added. + */ + ROUTE_ADDED, + + /** + * A mcast route has been removed. + */ + ROUTE_REMOVED, + + /** + * A source for a mcast route (ie. the subject) has been added. + */ + SOURCE_ADDED, + + /** + * A sink for a mcast route (ie. the subject) has been added. + */ + SINK_ADDED, + + /** + * A source for a mcast route (ie. the subject) has been removed. + */ + SINK_REMOVED + } + + private McastEvent(McastEvent.Type type, McastRoute subject) { + super(type, subject); + sink = Optional.empty(); + source = Optional.empty(); + } + + private McastEvent(McastEvent.Type type, McastRoute subject, long time) { + super(type, subject, time); + sink = Optional.empty(); + source = Optional.empty(); + } + + public McastEvent(McastEvent.Type type, McastRoute subject, + ConnectPoint sink, + ConnectPoint source) { + super(type, subject); + this.sink = Optional.ofNullable(sink); + this.source = Optional.ofNullable(source); + } + + public McastEvent(McastEvent.Type type, McastRoute subject, long time, + ConnectPoint sink, + ConnectPoint source) { + super(type, subject, time); + this.sink = Optional.ofNullable(sink); + this.source = Optional.ofNullable(source); + } + + /** + * The sink which has been removed or added. The field may not be set + * if the sink has not been detected yet or has been removed. + * + * @return an optional connect point + */ + public Optional sink() { + return sink; + } + + /** + * The source which has been removed or added. + + * @return an optional connect point + */ + public Optional source() { + return source; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("type", type()) + .add("route", subject()) + .add("source", source) + .add("sinks", sink).toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastListener.java new file mode 100644 index 00000000..06449b99 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastListener.java @@ -0,0 +1,26 @@ +/* + * 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.net.mcast; + +import com.google.common.annotations.Beta; +import org.onosproject.event.EventListener; + +/** + * A listener interface for multicast events. + */ +@Beta +public interface McastListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastRoute.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastRoute.java new file mode 100644 index 00000000..ff1292bf --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/McastRoute.java @@ -0,0 +1,117 @@ +/* + * 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.net.mcast; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import org.onlab.packet.IpPrefix; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An entity representing a multicast route consisting of a source + * and a multicast group address. + */ +@Beta +public class McastRoute { + + public enum Type { + /** + * Route originates from PIM. + */ + PIM, + + /** + * Route originates from IGMP. + */ + IGMP, + + /** + * Route originates from other config (ie. REST, CLI). + */ + STATIC + } + + private final IpPrefix source; + private final IpPrefix group; + private final Type type; + + public McastRoute(IpPrefix source, IpPrefix group, Type type) { + checkNotNull(source, "Multicast route must have a source"); + checkNotNull(group, "Multicast route must specify a group address"); + checkNotNull(type, "Must indicate what type of route"); + this.source = source; + this.group = group; + this.type = type; + } + + /** + * Fetches the source address of this route. + * + * @return an ip address + */ + public IpPrefix source() { + return source; + } + + /** + * Fetches the group address of this route. + * + * @return an ip address + */ + public IpPrefix group() { + return group; + } + + /** + * Obtains how this route was created. + * @return a type of route + + */ + public Type type() { + return type; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("source", source) + .add("group", group) + .add("origin", type) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + McastRoute that = (McastRoute) o; + return Objects.equal(source, that.source) && + Objects.equal(group, that.group) && + Objects.equal(type, that.type); + } + + @Override + public int hashCode() { + return Objects.hashCode(source, group, type); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/MulticastRouteService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/MulticastRouteService.java new file mode 100644 index 00000000..56e87c55 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/MulticastRouteService.java @@ -0,0 +1,84 @@ +/* + * 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.net.mcast; + +import com.google.common.annotations.Beta; +import org.onosproject.net.ConnectPoint; + +import java.util.List; + +/** + * A service interface for maintaining multicast information. + */ +@Beta +public interface MulticastRouteService { + + /** + * Adds a route to the information base. + * + * @param route a multicast route + */ + void add(McastRoute route); + + /** + * Removes a route from the information base. + * + * @param route a multicast route + */ + void remove(McastRoute route); + + /** + * Adds a source connection to the route from where the + * data stream is originating. + * + * @param route the multicast route + * @param connectPoint a source connect point + */ + void addSource(McastRoute route, ConnectPoint connectPoint); + + /** + * Adds a sink to the route to which a data stream should be + * sent to. + * + * @param route a multicast route + * @param connectPoint a sink connect point + */ + void addSink(McastRoute route, ConnectPoint connectPoint); + + /** + * Removes a sink from the route. + * + * @param route the multicast route + * @param connectPoint a sink connect point + */ + void removeSink(McastRoute route, ConnectPoint connectPoint); + + /** + * Find the data source association for this multicast route. + * + * @param route a multicast route + * @return a connect point + */ + ConnectPoint fetchSource(McastRoute route); + + /** + * Find the list of sinks for this route. + * + * @param route a multicast route + * @return a list of connect points + */ + List fetchSinks(McastRoute route); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/package-info.java new file mode 100644 index 00000000..e8dcc7b8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/mcast/package-info.java @@ -0,0 +1,20 @@ +/* + * 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. + */ + +/** + * External model entities of the multicast RIB. + */ +package org.onosproject.net.mcast; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java index 94cada47..51394c30 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java @@ -43,7 +43,8 @@ public final class DefaultMeterRequest implements MeterRequest { private DefaultMeterRequest(DeviceId deviceId, ApplicationId appId, Meter.Unit unit, boolean burst, - Collection bands, MeterContext context, Type op) { + Collection bands, MeterContext context, + Type op) { this.deviceId = deviceId; this.appId = appId; this.unit = unit; @@ -58,6 +59,7 @@ public final class DefaultMeterRequest implements MeterRequest { return deviceId; } + @Override public ApplicationId appId() { return appId; @@ -107,6 +109,7 @@ public final class DefaultMeterRequest implements MeterRequest { private Collection bands; private DeviceId deviceId; private MeterContext context; + private Optional desiredId = Optional.empty(); @Override diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterKey.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterKey.java new file mode 100644 index 00000000..5bc01b02 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterKey.java @@ -0,0 +1,72 @@ +/* + * 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.net.meter; + +import com.google.common.base.Objects; +import org.onosproject.net.DeviceId; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * A meter key represents a meter uniquely. + */ +public final class MeterKey { + + private final DeviceId deviceId; + private final MeterId id; + + private MeterKey(DeviceId deviceId, MeterId id) { + this.deviceId = deviceId; + this.id = id; + } + + public DeviceId deviceId() { + return deviceId; + } + + public MeterId meterId() { + return id; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MeterKey meterKey = (MeterKey) o; + return Objects.equal(deviceId, meterKey.deviceId) && + Objects.equal(id, meterKey.id); + } + + @Override + public int hashCode() { + return Objects.hashCode(deviceId, id); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("deviceId", deviceId) + .add("meterId", id).toString(); + } + + public static MeterKey key(DeviceId deviceId, MeterId id) { + return new MeterKey(deviceId, id); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterService.java index bdc90eb7..2e07cb67 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterService.java @@ -16,6 +16,7 @@ package org.onosproject.net.meter; import org.onosproject.event.ListenerService; +import org.onosproject.net.DeviceId; import java.util.Collection; @@ -46,10 +47,11 @@ public interface MeterService /** * Fetch the meter by the meter id. * + * @param deviceId a device id * @param id a meter id * @return a meter */ - Meter getMeter(MeterId id); + Meter getMeter(DeviceId deviceId, MeterId id); /** * Fetches all the meters. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java index 5112a4a3..f429e95a 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java @@ -57,12 +57,12 @@ public interface MeterStore extends Store { void updateMeterState(Meter meter); /** - * Obtains a meter matching the given meter id. + * Obtains a meter matching the given meter key. * - * @param meterId a meter id + * @param key a meter key * @return a meter */ - Meter getMeter(MeterId meterId); + Meter getMeter(MeterKey key); /** * Returns all meters stored in the store. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java index 618042a3..82d84743 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java @@ -124,6 +124,15 @@ public interface ResourceService { */ boolean release(ResourceConsumer consumer); + /** + * Returns resource allocation of the specified resource. + * + * @param resource resource to check the allocation + * @return allocation information enclosed by Optional. + * If the resource is not allocated, the return value is empty. + */ + Optional getResourceAllocation(ResourcePath resource); + /** * Returns allocated resources being as children of the specified parent and being the specified resource type. * diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProcessorEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProcessorEntry.java new file mode 100644 index 00000000..40386fb7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProcessorEntry.java @@ -0,0 +1,58 @@ +/* + * 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.net.packet; + +/** + * Packet processor entry tracking the processor, its priority and + * time consumption. + */ +public interface PacketProcessorEntry { + + /** + * Returns the packet processor. + * + * @return packet processor + */ + PacketProcessor processor(); + + /** + * Returns the packet processor priority. + * + * @return processor priority + */ + int priority(); + + /** + * Returns the number of invocations. + * + * @return number of invocations + */ + long invocations(); + + /** + * Returns the total time, in nanoseconds, spent processing packets. + * + * @return total time in nanos + */ + long totalNanos(); + + /** + * Returns the average time, in nanoseconds, spent processing packets. + * + * @return average time in nanos + */ + long averageNanos(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketService.java index 98f4d8e0..2e7a1b91 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketService.java @@ -20,7 +20,6 @@ import org.onosproject.core.ApplicationId; import org.onosproject.net.flow.TrafficSelector; import java.util.List; -import java.util.Map; /** * Service for intercepting data plane packets and for emitting synthetic @@ -52,13 +51,12 @@ public interface PacketService { void removeProcessor(PacketProcessor processor); /** - * Returns priority bindings of all registered packet processors. + * Returns priority bindings of all registered packet processor entries. * - * @return list of existing packet processors + * @return list of existing packet processor entries */ @Beta - // TODO: Consider returning list of PacketProcessorEntry with processor, priority and stats - Map getProcessors(); + List getProcessors(); /** * Requests that packets matching the given selector are punted from the diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStore.java index 97f7cb55..d83fc9a2 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStore.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStore.java @@ -37,17 +37,15 @@ public interface PacketStore extends Store { * Requests intercept of packets that match the given selector. * * @param request a packet request - * @return true if the first time the given selector was requested */ - boolean requestPackets(PacketRequest request); + void requestPackets(PacketRequest request); /** * Cancels intercept of packets that match the given selector. * * @param request a packet request - * @return true if there is no other application requesting the given selector */ - boolean cancelPackets(PacketRequest request); + void cancelPackets(PacketRequest request); /** * Obtains all existing requests in the system. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStoreDelegate.java index bf5c3cc0..2e59b19d 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStoreDelegate.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStoreDelegate.java @@ -21,4 +21,20 @@ import org.onosproject.store.StoreDelegate; * Packet store delegate abstraction. */ public interface PacketStoreDelegate extends StoreDelegate { + + /** + * Requests that packets matching to following request be collected + * from all switches. + * + * @param request packet request + */ + void requestPackets(PacketRequest request); + + /** + * Requests that packets matching to following request no longer be + * collected from any switches. + * + * @param request packet request + */ + void cancelPackets(PacketRequest request); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/IntentSetMultimap.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/IntentSetMultimap.java new file mode 100644 index 00000000..67c539df --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/IntentSetMultimap.java @@ -0,0 +1,47 @@ +/* + * 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.net.resource.device; + +import org.onosproject.net.intent.IntentId; + +import java.util.Set; + +public interface IntentSetMultimap { + + /** + * Allocates the mapping between the given intents. + * + * @param keyIntentId key intent ID + * @param valIntentId value intent ID + * @return true if mapping was successful, false otherwise + */ + boolean allocateMapping(IntentId keyIntentId, IntentId valIntentId); + + /** + * Returns the set of intents mapped to a lower intent. + * + * @param intentId intent ID + * @return set of intent IDs + */ + Set getMapping(IntentId intentId); + + /** + * Releases the mapping of the given intent. + * + * @param intentId intent ID + */ + void releaseMapping(IntentId intentId); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceRequest.java index 91cc3d19..e07309cb 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceRequest.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceRequest.java @@ -64,7 +64,7 @@ public class BandwidthResourceRequest implements ResourceRequest { if (obj == null || getClass() != obj.getClass()) { return false; } - final BandwidthResourceAllocation other = (BandwidthResourceAllocation) obj; + final BandwidthResourceRequest other = (BandwidthResourceRequest) obj; return Objects.equals(this.bandwidth, other.bandwidth()); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticService.java new file mode 100644 index 00000000..f59670bc --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticService.java @@ -0,0 +1,105 @@ +/* + * 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.net.statistic; + +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Device; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.TypedStoredFlowEntry; +import org.onosproject.net.flow.instructions.Instruction; + +import java.util.List; +import java.util.Map; + +/** + * Service for obtaining individual flow statistic information about device and link in the system. + * Basic statistics are obtained from the StatisticService + */ +public interface FlowStatisticService { + + /** + * Obtain the summary load list for the device with the given link. + * + * @param device the Device to query. + * @return map of summary flow entry load + */ + Map loadSummary(Device device); + + /** + * Obtain the summary load for the device with the given link or port. + * + * @param device the Device to query. + * @param pNumber the port number to query. + * @return summary flow entry load + */ + SummaryFlowEntryWithLoad loadSummary(Device device, PortNumber pNumber); + + /** + * Obtain the set of the flow type and load list for the device with the given link. + * + * @param device the Device to query. + * @param liveType the FlowLiveType to filter, null means no filtering . + * @param instType the InstructionType to filter, null means no filtering. + * @return map of flow entry load + */ + Map> loadAllByType(Device device, + TypedStoredFlowEntry.FlowLiveType liveType, + Instruction.Type instType); + + /** + * Obtain the flow type and load list for the device with the given link or port. + * + * @param device the Device to query. + * @param pNumber the port number of the Device to query + * @param liveType the FlowLiveType to filter, null means no filtering . + * @param instType the InstructionType to filter, null means no filtering. + * @return list of flow entry load + */ + List loadAllByType(Device device, PortNumber pNumber, + TypedStoredFlowEntry.FlowLiveType liveType, + Instruction.Type instType); + + /** + * Obtain the set of the flow type and load topn list for the device with the given link. + * + * @param device the Device to query. + * @param liveType the FlowLiveType to filter, null means no filtering . + * @param instType the InstructionType to filter, null means no filtering. + * @param topn the top number to filter, null means no filtering. + * @return map of flow entry load + */ + Map> loadTopnByType(Device device, + TypedStoredFlowEntry.FlowLiveType liveType, + Instruction.Type instType, + int topn); + + /** + * Obtain the flow type and load topn list for the device with the given link or port. + * + * @param device the Device to query. + * @param pNumber the port number of the Device to query + * @param liveType the FlowLiveType to filter, null means no filtering . + * @param instType the InstructionType to filter, null means no filtering. + * @return list of flow entry load + */ + List loadTopnByType(Device device, PortNumber pNumber, + TypedStoredFlowEntry.FlowLiveType liveType, + Instruction.Type instType, + int topn); +} + + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticStore.java new file mode 100644 index 00000000..3c2aa89b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/FlowStatisticStore.java @@ -0,0 +1,65 @@ +/* + * 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.net.statistic; + +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.flow.FlowEntry; +import org.onosproject.net.flow.FlowRule; + +import java.util.Set; + +/** + * Flow Store to house the computed statistics. + */ +public interface FlowStatisticStore { + /** + * Remove entries associated with this rule. + * + * @param rule {@link org.onosproject.net.flow.FlowRule} + */ + void removeFlowStatistic(FlowRule rule); + + /** + * Adds a flow stats observation for a flow rule. The previous flow will be removed. + * + * @param rule a {@link org.onosproject.net.flow.FlowEntry} + */ + void addFlowStatistic(FlowEntry rule); + + /** + * Updates a stats observation for a flow rule. The old flow stats will be moved to previous stats. + * + * @param rule a {@link org.onosproject.net.flow.FlowEntry} + */ + void updateFlowStatistic(FlowEntry rule); + + /** + * Fetches the current observed flow stats values. + * + * @param connectPoint the port to fetch information for + * @return set of current flow rules + */ + Set getCurrentFlowStatistic(ConnectPoint connectPoint); + + /** + * Fetches the current observed flow stats values. + * + * @param connectPoint the port to fetch information for + * @return set of current values + */ + Set getPreviousFlowStatistic(ConnectPoint connectPoint); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/SummaryFlowEntryWithLoad.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/SummaryFlowEntryWithLoad.java new file mode 100644 index 00000000..60da636a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/SummaryFlowEntryWithLoad.java @@ -0,0 +1,143 @@ +/* + * 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.net.statistic; + +import org.onosproject.net.ConnectPoint; + +/** + * Summary Load classified by flow live type. + */ +public class SummaryFlowEntryWithLoad { + private ConnectPoint cp; + private Load totalLoad; + private Load immediateLoad; + private Load shortLoad; + private Load midLoad; + private Load longLoad; + private Load unknownLoad; + + /** + * Creates a new summary flow entry having load for the given connect point and total load. + * + * @param cp connect point + * @param totalLoad total load + */ + public SummaryFlowEntryWithLoad(ConnectPoint cp, Load totalLoad) { + this.cp = cp; + this.totalLoad = totalLoad; + this.immediateLoad = new DefaultLoad(); + this.shortLoad = new DefaultLoad(); + this.midLoad = new DefaultLoad(); + this.longLoad = new DefaultLoad(); + this.unknownLoad = new DefaultLoad(); + } + + /** + * Creates a new summary flow entry having load for the given connect point + * and total, immediate, short, mid, and long load. + * + * @param cp connect point + * @param totalLoad total load + * @param immediateLoad immediate load + * @param shortLoad short load + * @param midLoad mid load + * @param longLoad long load + */ + public SummaryFlowEntryWithLoad(ConnectPoint cp, + Load totalLoad, Load immediateLoad, Load shortLoad, Load midLoad, Load longLoad) { + this.cp = cp; + this.totalLoad = totalLoad; + this.immediateLoad = immediateLoad; + this.shortLoad = shortLoad; + this.midLoad = midLoad; + this.longLoad = longLoad; + this.unknownLoad = new DefaultLoad(); + } + + /** + * Creates a new summary flow entry having load for the given connect point + * and total, immediate, short, mid, long, and unknown load. + * + * @param cp connect point + * @param totalLoad total load + * @param immediateLoad immediate load + * @param shortLoad short load + * @param midLoad mid load + * @param longLoad long load + * @param unknownLoad long load + */ + public SummaryFlowEntryWithLoad(ConnectPoint cp, + Load totalLoad, Load immediateLoad, + Load shortLoad, Load midLoad, Load longLoad, Load unknownLoad) { + this.cp = cp; + this.totalLoad = totalLoad; + this.immediateLoad = immediateLoad; + this.shortLoad = shortLoad; + this.midLoad = midLoad; + this.longLoad = longLoad; + this.unknownLoad = unknownLoad; + } + + /** + * Returns connect point. + */ + public ConnectPoint connectPoint() { + return cp; + } + + /** + * Returns total load of connect point. + */ + public Load totalLoad() { + return totalLoad; + } + + /** + * Returns immediate load of connect point. + */ + public Load immediateLoad() { + return immediateLoad; + } + + /** + * Returns short load of connect point. + */ + public Load shortLoad() { + return shortLoad; + } + + /** + * Returns mid load of connect point. + */ + public Load midLoad() { + return midLoad; + } + + /** + * Returns long load of connect point. + */ + public Load longLoad() { + return longLoad; + } + + /** + * Returns unknown load of connect point. + */ + public Load unknownLoad() { + return unknownLoad; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/TypedFlowEntryWithLoad.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/TypedFlowEntryWithLoad.java new file mode 100644 index 00000000..3e2dbdf8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/TypedFlowEntryWithLoad.java @@ -0,0 +1,143 @@ +/* + * 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.net.statistic; + +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.flow.FlowEntry; +import org.onosproject.net.flow.TypedStoredFlowEntry; +import org.onosproject.net.flow.DefaultTypedFlowEntry; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Load of flow entry of flow live type. + */ +public class TypedFlowEntryWithLoad { + private ConnectPoint cp; + private TypedStoredFlowEntry tfe; + private Load load; + + //TODO: make this variables class, and share with NewAdaptivceFlowStatsCollector class + private static final int CAL_AND_POLL_INTERVAL = 5; // means SHORT_POLL_INTERVAL + private static final int MID_POLL_INTERVAL = 10; + private static final int LONG_POLL_INTERVAL = 15; + + + public TypedFlowEntryWithLoad(ConnectPoint cp, TypedStoredFlowEntry tfe, Load load) { + this.cp = cp; + this.tfe = tfe; + this.load = load; + } + + public TypedFlowEntryWithLoad(ConnectPoint cp, TypedStoredFlowEntry tfe) { + this.cp = cp; + this.tfe = tfe; + this.load = new DefaultLoad(tfe.bytes(), 0, typedPollInterval(tfe)); + } + + public TypedFlowEntryWithLoad(ConnectPoint cp, FlowEntry fe) { + this.cp = cp; + this.tfe = newTypedStoredFlowEntry(fe); + this.load = new DefaultLoad(fe.bytes(), 0, typedPollInterval(this.tfe)); + } + + public ConnectPoint connectPoint() { + return cp; + } + public TypedStoredFlowEntry typedStoredFlowEntry() { + return tfe; + } + public Load load() { + return load; + } + public void setLoad(Load load) { + this.load = load; + } + + /** + * Returns short polling interval. + */ + public static int shortPollInterval() { + return CAL_AND_POLL_INTERVAL; + } + + /** + * Returns mid polling interval. + */ + public static int midPollInterval() { + return MID_POLL_INTERVAL; + } + + /** + * Returns long polling interval. + */ + public static int longPollInterval() { + return LONG_POLL_INTERVAL; + } + + /** + * Returns average polling interval. + */ + public static int avgPollInterval() { + return (CAL_AND_POLL_INTERVAL + MID_POLL_INTERVAL + LONG_POLL_INTERVAL) / 3; + } + + /** + * Returns current typed flow entry's polling interval. + * + * @param tfe typed flow entry + */ + public static long typedPollInterval(TypedStoredFlowEntry tfe) { + checkNotNull(tfe, "TypedStoredFlowEntry cannot be null"); + + switch (tfe.flowLiveType()) { + case LONG_FLOW: + return LONG_POLL_INTERVAL; + case MID_FLOW: + return MID_POLL_INTERVAL; + case SHORT_FLOW: + case IMMEDIATE_FLOW: + default: + return CAL_AND_POLL_INTERVAL; + } + } + + /** + * Creates a new typed flow entry with the given flow entry fe. + * + * @param fe flow entry + */ + public static TypedStoredFlowEntry newTypedStoredFlowEntry(FlowEntry fe) { + if (fe == null) { + return null; + } + + long life = fe.life(); + + if (life >= LONG_POLL_INTERVAL) { + return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.LONG_FLOW); + } else if (life >= MID_POLL_INTERVAL) { + return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.MID_FLOW); + } else if (life >= CAL_AND_POLL_INTERVAL) { + return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.SHORT_FLOW); + } else if (life >= 0) { + return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.IMMEDIATE_FLOW); + } else { // life < 0 + return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.UNKNOWN_FLOW); + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultGraphDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultGraphDescription.java index f1e20dac..965c05d4 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultGraphDescription.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultGraphDescription.java @@ -45,23 +45,6 @@ public class DefaultGraphDescription extends AbstractDescription private final Map vertexesById = Maps.newHashMap(); - /** - * Creates a minimal topology graph description to allow core to construct - * and process the topology graph. - * - * @param nanos time in nanos of when the topology description was created - * @param devices collection of infrastructure devices - * @param links collection of infrastructure links - * @param annotations optional key/value annotations map - * @deprecated in Cardinal Release - */ - @Deprecated - public DefaultGraphDescription(long nanos, Iterable devices, - Iterable links, - SparseAnnotations... annotations) { - this(nanos, System.currentTimeMillis(), devices, links, annotations); - } - /** * Creates a minimal topology graph description to allow core to construct * and process the topology graph. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathService.java index be8c7cfc..0bd4d75d 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathService.java @@ -15,9 +15,12 @@ */ package org.onosproject.net.topology; +import org.onosproject.net.DisjointPath; import org.onosproject.net.ElementId; +import org.onosproject.net.Link; import org.onosproject.net.Path; +import java.util.Map; import java.util.Set; /** @@ -41,11 +44,58 @@ public interface PathService { * edge-weight entity, between the specified source and destination * network elements. * - * @param src source element - * @param dst destination element + * @param src source element + * @param dst destination element * @param weight edge-weight entity * @return set of all shortest paths between the two element */ Set getPaths(ElementId src, ElementId dst, LinkWeight weight); + /** + * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, + * between the specified source and destination devices. + * + * @param src source device + * @param dst destination device + * @return set of all shortest paths between the two devices + */ + Set getDisjointPaths(ElementId src, ElementId dst); + + /** + * Returns the set of all disjoint shortest path pairs, computed using the supplied + * edge-weight entity, between the specified source and destination devices. + * + * @param src source device + * @param dst destination device + * @param weight edge-weight entity + * @return set of all shortest paths between the two devices + */ + Set getDisjointPaths(ElementId src, ElementId dst, + LinkWeight weight); + + /** + * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, + * between the specified source and destination devices. + * + * @param src source device + * @param dst destination device + * @param riskProfile map of edges to risk profiles + * @return set of all shortest paths between the two devices + */ + Set getDisjointPaths(ElementId src, ElementId dst, + Map riskProfile); + + /** + * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, + * between the specified source and destination devices. + * + * @param src source device + * @param dst destination device + * @param weight edge-weight entity + * @param riskProfile map of edges to risk profiles + * @return set of all shortest paths between the two devices + */ + Set getDisjointPaths(ElementId src, ElementId dst, + LinkWeight weight, Map riskProfile); + } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java index 41eac2c4..466e4f9b 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java @@ -18,16 +18,18 @@ package org.onosproject.net.topology; import org.onosproject.event.ListenerService; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; +import org.onosproject.net.DisjointPath; import org.onosproject.net.Link; import org.onosproject.net.Path; +import java.util.Map; import java.util.Set; /** * Service for providing network topology information. */ public interface TopologyService - extends ListenerService { + extends ListenerService { /** * Returns the current topology descriptor. @@ -72,8 +74,8 @@ public interface TopologyService /** * Returns the set of devices that belong to the specified cluster. * - * @param topology topology descriptor - * @param cluster topology cluster + * @param topology topology descriptor + * @param cluster topology cluster * @return set of cluster devices */ Set getClusterDevices(Topology topology, TopologyCluster cluster); @@ -81,8 +83,8 @@ public interface TopologyService /** * Returns the set of links that form the specified cluster. * - * @param topology topology descriptor - * @param cluster topology cluster + * @param topology topology descriptor + * @param cluster topology cluster * @return set of cluster links */ Set getClusterLinks(Topology topology, TopologyCluster cluster); @@ -111,6 +113,57 @@ public interface TopologyService Set getPaths(Topology topology, DeviceId src, DeviceId dst, LinkWeight weight); + /** + * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, + * between the specified source and destination devices. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @return set of all shortest paths between the two devices + */ + Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst); + + /** + * Returns the set of all disjoint shortest path pairs, computed using the supplied + * edge-weight entity, between the specified source and destination devices. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @param weight edge-weight entity + * @return set of all shortest paths between the two devices + */ + Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight); + + /** + * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, + * between the specified source and destination devices. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @param riskProfile map of edges to risk profiles + * @return set of all shortest paths between the two devices + */ + Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + Map riskProfile); + + /** + * Returns the set of all disjoint shortest path pairs, precomputed in terms of hop-count, + * between the specified source and destination devices. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @param weight edge-weight entity + * @param riskProfile map of edges to risk profiles + * @return set of all shortest paths between the two devices + */ + Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight, Map riskProfile); + /** * Indicates whether the specified connection point is part of the network * infrastructure or part of network edge. diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java index 983e616e..039a205c 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java @@ -20,11 +20,13 @@ import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; import org.onosproject.net.Link; import org.onosproject.net.Path; +import org.onosproject.net.DisjointPath; import org.onosproject.net.provider.ProviderId; import org.onosproject.store.Store; import java.util.List; import java.util.Set; +import java.util.Map; /** * Manages inventory of topology snapshots; not intended for direct use. @@ -111,6 +113,59 @@ public interface TopologyStore extends Store getPaths(Topology topology, DeviceId src, DeviceId dst, LinkWeight weight); + /** + * Computes and returns the set of disjoint shortest path pairs + * between src and dst. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @param weight link weight function + * @return set of shortest paths + */ + Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight); + + /** + * Computes and returns the set of disjoint shortest path pairs + * between src and dst. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @return set of shortest paths + */ + Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst); + + /** + * Computes and returns the set of SRLG disjoint shortest path pairs between source + * and dst, given a mapping of edges to SRLG risk groups. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @param weight link weight function + * @param riskProfile map of edges to objects. Edges that map to the same object will + * be treated as if they were in the same risk group. + * @return set of shortest paths + */ + Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight, Map riskProfile); + + /** + * Returns the set of pre-computed SRLG shortest paths between src and dest. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @param riskProfile map of edges to objects. Edges that map to the same object will + * be treated as if they were in the same risk group. + * @return set of shortest paths + */ + Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + Map riskProfile); + + /** * Indicates whether the given connect point is part of the network fabric. * diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncAtomicCounter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncAtomicCounter.java index a879cc59..c0df7134 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncAtomicCounter.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncAtomicCounter.java @@ -58,4 +58,21 @@ public interface AsyncAtomicCounter { * @return current value */ CompletableFuture get(); + + + /** + * Atomically sets the given value to the current value. + * + * @return future void + */ + CompletableFuture set(long value); + + /** + * Atomically sets the given counter to the updated value if the current value is the expected value, otherwise + * no change occurs. + * @param expectedValue the expected current value of the counter + * @param updateValue the new value to be set + * @return true if the update occurred and the expected value was equal to the current value, false otherwise + */ + CompletableFuture compareAndSet(long expectedValue, long updateValue); } diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounter.java index f620e082..3c9e02c8 100644 --- a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounter.java +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounter.java @@ -50,6 +50,22 @@ public interface AtomicCounter { */ long addAndGet(long delta); + /** + * Atomically sets the given value to the current value. + * + * @param value the value to set + */ + void set(long value); + + /** + * Atomically sets the given counter to the updated value if the current value is the expected value, otherwise + * no change occurs. + * @param expectedValue the expected current value of the counter + * @param updateValue the new value to be set + * @return true if the update occurred and the expected value was equal to the current value, false otherwise + */ + boolean compareAndSet(long expectedValue, long updateValue); + /** * Returns the current value of the counter without modifying it. * diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexExecutionService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexExecutionService.java new file mode 100644 index 00000000..d05f3b91 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexExecutionService.java @@ -0,0 +1,34 @@ +/* + * 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.store.service; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +/** + * Service for mutually exclusive job execution. + */ +public interface MutexExecutionService { + + /** + * Runs the specified task in a mutually exclusive fashion. + * @param task task to run + * @param exclusionPath path on which different instances synchronize + * @param executor executor to use for running the task + * @return future that is completed when the task execution completes. + */ + CompletableFuture execute(MutexTask task, String exclusionPath, Executor executor); +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexTask.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexTask.java new file mode 100644 index 00000000..ba5ee47f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MutexTask.java @@ -0,0 +1,39 @@ +/* + * 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.store.service; + +/** + * The MutexTask interface should be implemented by any class whose + * instances distributed across controllers are intended to be executed + * in a mutually exclusive fashion. + */ +public interface MutexTask { + + /** + * Begins the execution of a mutually exclusive task. + * The start method will be called once the "lock" is acquired. + * After the start method returns the lock is released and some other + * instance can take over execution. + */ + void start(); + + /** + * This method will be called when exclusivity of task execution + * can no longer be guaranteed. The implementation should take necessary steps + * to halt task execution in order to ensure correctness. + */ + void stop(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/NumberFormatter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/NumberFormatter.java new file mode 100644 index 00000000..76f42466 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/NumberFormatter.java @@ -0,0 +1,50 @@ +/* + * 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.ui.table.cell; + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +/** + * Formats number using the specified format string". + */ +public final class NumberFormatter extends AbstractCellFormatter { + + private final NumberFormat format; + + /** + * Creates a formatter using a default decimal format. + */ + public NumberFormatter() { + this(new DecimalFormat("#,##0.00000")); + } + + /** + * Creates a formatter using the specified format. + * + * @param format number format + */ + public NumberFormatter(NumberFormat format) { + this.format = format; + } + + @Override + protected String nonNullFormat(Object value) { + return format.format(value); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java index a1abd188..0fccef81 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java @@ -17,10 +17,13 @@ package org.onosproject.cfg; import java.util.Set; +import com.google.common.collect.ImmutableSet; + /** * Adapter for testing against component configuration service. */ public class ComponentConfigAdapter implements ComponentConfigService { + @Override public Set getComponentNames() { return null; @@ -38,7 +41,7 @@ public class ComponentConfigAdapter implements ComponentConfigService { @Override public Set getProperties(String componentName) { - return null; + return ImmutableSet.of(); } @Override @@ -46,6 +49,10 @@ public class ComponentConfigAdapter implements ComponentConfigService { } + @Override + public void preSetProperty(String componentName, String name, String value) { + } + @Override public void unsetProperty(String componentName, String name) { diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/behaviour/ControllerInfoTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/behaviour/ControllerInfoTest.java new file mode 100644 index 00000000..ece7f199 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/behaviour/ControllerInfoTest.java @@ -0,0 +1,112 @@ +/* + * 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.net.behaviour; + + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.onlab.packet.IpAddress; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.*; + +/** + * Test for ControllerInfo class. + */ +public class ControllerInfoTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void tcpSslFormat() { + String target = "tcp:192.168.1.1:6653"; + ControllerInfo controllerInfo = new ControllerInfo(target); + assertEquals("wrong type", controllerInfo.type(), "tcp"); + assertEquals("wrong ip", controllerInfo.ip(), IpAddress.valueOf("192.168.1.1")); + assertEquals("wrong port", controllerInfo.port(), 6653); + + } + + @Test + public void ptcpPsslFormat() { + String target = "ptcp:6653:192.168.1.1"; + ControllerInfo controllerInfo = new ControllerInfo(target); + assertEquals("wrong type", controllerInfo.type(), "ptcp"); + assertEquals("wrong ip", controllerInfo.ip(), IpAddress.valueOf("192.168.1.1")); + assertEquals("wrong port", controllerInfo.port(), 6653); + + } + + @Test + public void unixFormat() { + String target = "unix:file"; + thrown.expect(IllegalArgumentException.class); + ControllerInfo controllerInfo = new ControllerInfo(target); + assertTrue("wrong type", controllerInfo.type().contains("unix")); + assertNull("wrong ip", controllerInfo.ip()); + assertEquals("wrong port", controllerInfo.port(), -1); + + } + + @Test + public void defaultValues() { + String target = "tcp:192.168.1.1"; + ControllerInfo controllerInfo = new ControllerInfo(target); + assertEquals("wrong type", controllerInfo.type(), "tcp"); + assertEquals("wrong ip", controllerInfo.ip(), IpAddress.valueOf("192.168.1.1")); + assertEquals("wrong port", controllerInfo.port(), 6653); + String target1 = "ptcp:5000:"; + ControllerInfo controllerInfo2 = new ControllerInfo(target1); + assertEquals("wrong type", controllerInfo2.type(), "ptcp"); + assertEquals("wrong ip", controllerInfo2.ip(), IpAddress.valueOf("0.0.0.0")); + assertEquals("wrong port", controllerInfo2.port(), 5000); + String target2 = "ptcp:"; + ControllerInfo controllerInfo3 = new ControllerInfo(target2); + assertEquals("wrong type", controllerInfo3.type(), "ptcp"); + assertEquals("wrong ip", controllerInfo3.ip(), IpAddress.valueOf("0.0.0.0")); + assertEquals("wrong port", controllerInfo3.port(), 6653); + } + + + @Test + public void testEquals() { + String target1 = "ptcp:6653:192.168.1.1"; + ControllerInfo controllerInfo1 = new ControllerInfo(target1); + String target2 = "ptcp:6653:192.168.1.1"; + ControllerInfo controllerInfo2 = new ControllerInfo(target2); + assertTrue("wrong equals method", controllerInfo1.equals(controllerInfo2)); + } + + @Test + public void testListEquals() { + String target1 = "ptcp:6653:192.168.1.1"; + ControllerInfo controllerInfo1 = new ControllerInfo(target1); + String target2 = "ptcp:6653:192.168.1.1"; + ControllerInfo controllerInfo2 = new ControllerInfo(target2); + String target3 = "tcp:192.168.1.1:6653"; + ControllerInfo controllerInfo3 = new ControllerInfo(target3); + String target4 = "tcp:192.168.1.1:6653"; + ControllerInfo controllerInfo4 = new ControllerInfo(target4); + List list1 = new ArrayList<>(Arrays.asList(controllerInfo1, controllerInfo3)); + List list2 = new ArrayList<>(Arrays.asList(controllerInfo2, controllerInfo4)); + assertTrue("wrong equals list method", list1.equals(list2)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java index b70d14e8..73072583 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java @@ -29,7 +29,7 @@ public class NetworkConfigServiceAdapter implements NetworkConfigService { } @Override - public SubjectFactory getSubjectFactory(String subjectKey) { + public SubjectFactory getSubjectFactory(String subjectClassKey) { return null; } @@ -39,7 +39,7 @@ public class NetworkConfigServiceAdapter implements NetworkConfigService { } @Override - public Class getConfigClass(String subjectKey, String configKey) { + public Class getConfigClass(String subjectClassKey, String configKey) { return null; } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java index b871397b..10c5a637 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java @@ -267,29 +267,5 @@ public class DefaultTrafficSelectorTest { selector = DefaultTrafficSelector.builder() .add(Criteria.matchLambda(new IndexedLambda(shortValue))).build(); assertThat(selector, hasCriterionWithType(Type.OCH_SIGID)); - - selector = DefaultTrafficSelector.builder() - .add(Criteria.matchOpticalSignalType(shortValue)).build(); - assertThat(selector, hasCriterionWithType(Type.OCH_SIGTYPE)); - } - - /** - * Tests the traffic selector builder. - */ - @Test - public void testTrafficSelectorBuilder() { - TrafficSelector selector; - final short shortValue = 33; - - final TrafficSelector baseSelector = DefaultTrafficSelector.builder() - .add(Criteria.matchLambda(new IndexedLambda(shortValue))).build(); - selector = DefaultTrafficSelector.builder(baseSelector) - .build(); - assertThat(selector, hasCriterionWithType(Type.OCH_SIGID)); - - final Criterion criterion = Criteria.matchLambda(shortValue); - selector = DefaultTrafficSelector.builder() - .add(criterion).build(); - assertThat(selector, hasCriterionWithType(Type.OCH_SIGID)); } } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java index c7b78791..56e59118 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java @@ -35,17 +35,14 @@ public class FlowRuleServiceAdapter implements FlowRuleService { @Override public void applyFlowRules(FlowRule... flowRules) { - } @Override public void removeFlowRules(FlowRule... flowRules) { - } @Override public void removeFlowRulesById(ApplicationId appId) { - } @Override @@ -60,16 +57,18 @@ public class FlowRuleServiceAdapter implements FlowRuleService { @Override public void apply(FlowRuleOperations ops) { - } @Override public void addListener(FlowRuleListener listener) { - } @Override public void removeListener(FlowRuleListener listener) { + } + @Override + public Iterable getFlowTableStatistics(DeviceId deviceId) { + return null; } } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java index ee294f6f..95d605c6 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java @@ -225,12 +225,6 @@ public class CriteriaTest { Criterion matchIpv6ExthdrFlags2 = Criteria.matchIPv6ExthdrFlags(ipv6ExthdrFlags2); - int lambda1 = 1; - int lambda2 = 2; - Criterion matchLambda1 = Criteria.matchLambda(lambda1); - Criterion sameAsMatchLambda1 = Criteria.matchLambda(lambda1); - Criterion matchLambda2 = Criteria.matchLambda(lambda2); - Criterion matchOchSignalType1 = Criteria.matchOchSignalType(OchSignalType.FIXED_GRID); Criterion sameAsMatchOchSignalType1 = Criteria.matchOchSignalType(OchSignalType.FIXED_GRID); Criterion matchOchSignalType2 = Criteria.matchOchSignalType(OchSignalType.FLEX_GRID); @@ -239,12 +233,6 @@ public class CriteriaTest { Criterion sameAsMatchIndexedLambda1 = Criteria.matchLambda(Lambda.indexedLambda(1)); Criterion matchIndexedLambda2 = Criteria.matchLambda(Lambda.indexedLambda(2)); - short signalLambda1 = 1; - short signalLambda2 = 2; - Criterion matchSignalLambda1 = Criteria.matchOpticalSignalType(signalLambda1); - Criterion sameAsMatchSignalLambda1 = Criteria.matchOpticalSignalType(signalLambda1); - Criterion matchSignalLambda2 = Criteria.matchOpticalSignalType(signalLambda2); - Criterion matchOchSignal1 = Criteria.matchLambda(Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, 4, 8)); Criterion sameAsMatchOchSignal1 = @@ -306,7 +294,6 @@ public class CriteriaTest { assertThatClassIsImmutable(MplsCriterion.class); assertThatClassIsImmutable(IPv6ExthdrFlagsCriterion.class); assertThatClassIsImmutable(LambdaCriterion.class); - assertThatClassIsImmutable(OpticalSignalTypeCriterion.class); } // PortCriterion class @@ -1057,32 +1044,6 @@ public class CriteriaTest { .testEquals(); } - // LambdaCriterion class - - /** - * Test the matchLambda method. - */ - @Test - public void testMatchLambdaMethod() { - Criterion matchLambda = Criteria.matchLambda(lambda1); - LambdaCriterion lambdaCriterion = - checkAndConvert(matchLambda, - Criterion.Type.OCH_SIGID, - LambdaCriterion.class); - assertThat(lambdaCriterion.lambda(), is(equalTo(lambda1))); - } - - /** - * Test the equals() method of the LambdaCriterion class. - */ - @Test - public void testLambdaCriterionEquals() { - new EqualsTester() - .addEqualityGroup(matchLambda1, sameAsMatchLambda1) - .addEqualityGroup(matchLambda2) - .testEquals(); - } - @Test public void testIndexedLambdaCriterionEquals() { new EqualsTester() @@ -1109,30 +1070,4 @@ public class CriteriaTest { .addEqualityGroup(matchOchSignalType2) .testEquals(); } - - // OpticalSignalTypeCriterion class - - /** - * Test the matchOpticalSignalType method. - */ - @Test - public void testMatchOpticalSignalTypeMethod() { - Criterion matchLambda = Criteria.matchOpticalSignalType(signalLambda1); - OpticalSignalTypeCriterion opticalSignalTypeCriterion = - checkAndConvert(matchLambda, - Criterion.Type.OCH_SIGTYPE, - OpticalSignalTypeCriterion.class); - assertThat(opticalSignalTypeCriterion.signalType(), is(equalTo(signalLambda1))); - } - - /** - * Test the equals() method of the OpticalSignalTypeCriterion class. - */ - @Test - public void testOpticalSignalTypeCriterionEquals() { - new EqualsTester() - .addEqualityGroup(matchSignalLambda1, sameAsMatchSignalLambda1) - .addEqualityGroup(matchSignalLambda2) - .testEquals(); - } } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java index ac4ecff3..d42e22fa 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java @@ -17,7 +17,6 @@ package org.onosproject.net.intent; import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableSet; - import org.onlab.util.Bandwidth; import org.onosproject.core.DefaultGroupId; import org.onosproject.core.GroupId; @@ -37,6 +36,9 @@ import org.onosproject.net.flow.criteria.Criterion.Type; import org.onosproject.net.flow.instructions.Instruction; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.flow.instructions.Instructions.MetadataInstruction; +import org.onosproject.net.resource.ResourceAllocation; +import org.onosproject.net.resource.ResourceRequest; +import org.onosproject.net.resource.ResourceType; import org.onosproject.net.resource.link.BandwidthResource; import org.onosproject.net.resource.link.BandwidthResourceRequest; import org.onosproject.net.resource.link.LambdaResource; @@ -48,13 +50,10 @@ import org.onosproject.net.resource.link.LinkResourceRequest; import org.onosproject.net.resource.link.LinkResourceService; import org.onosproject.net.resource.link.MplsLabel; import org.onosproject.net.resource.link.MplsLabelResourceAllocation; -import org.onosproject.net.resource.ResourceAllocation; -import org.onosproject.net.resource.ResourceRequest; -import org.onosproject.net.resource.ResourceType; import org.onosproject.net.topology.DefaultTopologyEdge; import org.onosproject.net.topology.DefaultTopologyVertex; import org.onosproject.net.topology.LinkWeight; -import org.onosproject.net.topology.PathService; +import org.onosproject.net.topology.PathServiceAdapter; import org.onosproject.net.topology.TopologyVertex; import org.onosproject.store.Timestamp; @@ -68,9 +67,7 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; -import static org.onosproject.net.NetTestTools.createPath; -import static org.onosproject.net.NetTestTools.did; -import static org.onosproject.net.NetTestTools.link; +import static org.onosproject.net.NetTestTools.*; /** * Common mocks used by the intent framework tests. @@ -134,7 +131,7 @@ public class IntentTestsMocks { /** * Mock path service for creating paths within the test. */ - public static class MockPathService implements PathService { + public static class MockPathService extends PathServiceAdapter { final String[] pathHops; final String[] reversePathHops; @@ -424,7 +421,7 @@ public class IntentTestsMocks { } final MockFlowRule other = (MockFlowRule) obj; return Objects.equals(this.timestamp, other.timestamp) && - this.id == other.id; + this.id == other.id; } @Override @@ -450,7 +447,7 @@ public class IntentTestsMocks { public MockIntent(Long number) { super(NetTestTools.APP_ID, null, Collections.emptyList(), - Intent.DEFAULT_INTENT_PRIORITY); + Intent.DEFAULT_INTENT_PRIORITY); this.number = number; } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java index c4386593..2993ce6b 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java @@ -19,7 +19,6 @@ import org.onosproject.core.ApplicationId; import org.onosproject.net.flow.TrafficSelector; import java.util.List; -import java.util.Map; /** * Test adapter for packet service. @@ -34,7 +33,7 @@ public class PacketServiceAdapter implements PacketService { } @Override - public Map getProcessors() { + public List getProcessors() { return null; } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultGraphDescriptionTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultGraphDescriptionTest.java index 8b0f8f05..f3958491 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultGraphDescriptionTest.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultGraphDescriptionTest.java @@ -41,7 +41,7 @@ public class DefaultGraphDescriptionTest { @Test public void basics() { DefaultGraphDescription desc = - new DefaultGraphDescription(4321L, ImmutableSet.of(DEV1, DEV2, DEV3), + new DefaultGraphDescription(4321L, System.currentTimeMillis(), ImmutableSet.of(DEV1, DEV2, DEV3), ImmutableSet.of(L1, L2)); assertEquals("incorrect time", 4321L, desc.timestamp()); assertEquals("incorrect vertex count", 3, desc.vertexes().size()); @@ -50,7 +50,7 @@ public class DefaultGraphDescriptionTest { @Test public void missingVertex() { - GraphDescription desc = new DefaultGraphDescription(4321L, + GraphDescription desc = new DefaultGraphDescription(4321L, System.currentTimeMillis(), ImmutableSet.of(DEV1, DEV3), ImmutableSet.of(L1, L2)); assertEquals("incorrect time", 4321L, desc.timestamp()); diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/PathServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/PathServiceAdapter.java new file mode 100644 index 00000000..6a8e586f --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/PathServiceAdapter.java @@ -0,0 +1,62 @@ +/* + * 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.net.topology; + +import org.onosproject.net.DisjointPath; +import org.onosproject.net.ElementId; +import org.onosproject.net.Link; +import org.onosproject.net.Path; + +import java.util.Map; +import java.util.Set; + +/** + * Test adapter for path service. + */ +public class PathServiceAdapter implements PathService { + @Override + public Set getPaths(ElementId src, ElementId dst) { + return null; + } + + @Override + public Set getPaths(ElementId src, ElementId dst, LinkWeight weight) { + return null; + } + + @Override + public Set getDisjointPaths(ElementId src, ElementId dst) { + return null; + } + + @Override + public Set getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight) { + return null; + } + + @Override + public Set getDisjointPaths(ElementId src, ElementId dst, + Map riskProfile) { + return null; + } + + @Override + public Set getDisjointPaths(ElementId src, ElementId dst, + LinkWeight weight, + Map riskProfile) { + return null; + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java index 07e67842..72cc67d7 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java @@ -17,9 +17,11 @@ package org.onosproject.net.topology; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; +import org.onosproject.net.DisjointPath; import org.onosproject.net.Link; import org.onosproject.net.Path; +import java.util.Map; import java.util.Set; /** @@ -89,4 +91,28 @@ public class TopologyServiceAdapter implements TopologyService { public void removeListener(TopologyListener listener) { } + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst) { + return null; + } + + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, + DeviceId dst, LinkWeight weight) { + return null; + } + + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + Map riskProfile) { + return null; + } + + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, + DeviceId dst, LinkWeight weight, + Map riskProfile) { + return null; + } + } diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestAtomicCounter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestAtomicCounter.java index 01209be2..8c577df9 100644 --- a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestAtomicCounter.java +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestAtomicCounter.java @@ -47,6 +47,16 @@ public final class TestAtomicCounter implements AtomicCounter { return value.addAndGet(delta); } + @Override + public void set(long value) { + this.value.set(value); + } + + @Override + public boolean compareAndSet(long expectedValue, long updateValue) { + return value.compareAndSet(expectedValue, updateValue); + } + @Override public long get() { return value.get(); diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java index eb53152e..3433b3b7 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java @@ -16,6 +16,7 @@ package org.onosproject.codec.impl; import com.google.common.collect.ImmutableSet; + import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -36,6 +37,7 @@ import org.onosproject.net.Port; import org.onosproject.net.driver.Driver; import org.onosproject.net.flow.FlowEntry; import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.TableStatisticsEntry; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.flow.criteria.Criterion; @@ -99,6 +101,7 @@ public class CodecManager implements CodecService { registerCodec(Driver.class, new DriverCodec()); registerCodec(GroupBucket.class, new GroupBucketCodec()); registerCodec(Load.class, new LoadCodec()); + registerCodec(TableStatisticsEntry.class, new TableStatisticsEntryCodec()); log.info("Started"); } diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java index d61cf38b..d12e4ad8 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java @@ -215,6 +215,7 @@ public final class EncodeInstructionCodecHelper { break; case DROP: + case NOACTION: break; case L0MODIFICATION: diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TableStatisticsEntryCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TableStatisticsEntryCodec.java new file mode 100644 index 00000000..7834ceb1 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TableStatisticsEntryCodec.java @@ -0,0 +1,46 @@ +/* + * 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.codec.impl; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.flow.TableStatisticsEntry; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Table statistics entry JSON codec. + */ +public final class TableStatisticsEntryCodec extends JsonCodec { + + @Override + public ObjectNode encode(TableStatisticsEntry entry, CodecContext context) { + checkNotNull(entry, "Table Statistics entry cannot be null"); + + final ObjectNode result = context.mapper().createObjectNode() + .put("tableId", entry.tableId()) + .put("deviceId", entry.deviceId().toString()) + .put("activeEntries", entry.activeFlowEntries()) + .put("packetsLookedUp", entry.packetsLookedup()) + .put("packetsMatched", entry.packetsMatched()); + + return result; + } + +} + diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopology.java b/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopology.java index bdf7d732..3c5c540d 100644 --- a/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopology.java +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopology.java @@ -23,14 +23,19 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.ImmutableSetMultimap.Builder; import org.onlab.graph.DijkstraGraphSearch; +import org.onlab.graph.DisjointPathPair; import org.onlab.graph.GraphPathSearch; import org.onlab.graph.GraphPathSearch.Result; +import org.onlab.graph.SRLGGraphSearch; +import org.onlab.graph.SuurballeGraphSearch; import org.onlab.graph.TarjanGraphSearch; import org.onlab.graph.TarjanGraphSearch.SCCResult; import org.onosproject.net.AbstractModel; import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultDisjointPath; import org.onosproject.net.DefaultPath; import org.onosproject.net.DeviceId; +import org.onosproject.net.DisjointPath; import org.onosproject.net.Link; import org.onosproject.net.Path; import org.onosproject.net.provider.ProviderId; @@ -45,10 +50,11 @@ import org.onosproject.net.topology.TopologyEdge; import org.onosproject.net.topology.TopologyGraph; import org.onosproject.net.topology.TopologyVertex; -import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Preconditions.checkArgument; @@ -67,6 +73,9 @@ public class DefaultTopology extends AbstractModel implements Topology { private static final DijkstraGraphSearch DIJKSTRA = new DijkstraGraphSearch<>(); private static final TarjanGraphSearch TARJAN = new TarjanGraphSearch<>(); + private static final SuurballeGraphSearch SUURBALLE = + new SuurballeGraphSearch<>(); + private final long time; private final long creationTime; @@ -315,15 +324,135 @@ public class DefaultTopology extends AbstractModel implements Topology { return builder.build(); } + /** + * /** + * Returns the set of pre-computed shortest disjoint path pairs between source and + * destination devices. + * + * @param src source device + * @param dst destination device + * @return set of shortest disjoint path pairs + */ + public Set getDisjointPaths(DeviceId src, DeviceId dst) { + return getDisjointPaths(src, dst, (LinkWeight) null); + } + + /** + * Computes on-demand the set of shortest disjoint path pairs between source and + * destination devices. + * + * @param src source device + * @param dst destination device + * @param weight link weight function + * @return set of disjoint shortest path pairs + */ + public Set getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight) { + final DefaultTopologyVertex srcV = new DefaultTopologyVertex(src); + final DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst); + Set vertices = graph.getVertexes(); + if (!vertices.contains(srcV) || !vertices.contains(dstV)) { + // src or dst not part of the current graph + return ImmutableSet.of(); + } + + GraphPathSearch.Result result = + SUURBALLE.search(graph, srcV, dstV, weight, ALL_PATHS); + ImmutableSet.Builder builder = ImmutableSet.builder(); + for (org.onlab.graph.Path path : result.paths()) { + builder.add(networkDisjointPath((org.onlab.graph.DisjointPathPair) path)); + } + return builder.build(); + } + + /** + * Computes on-demand the set of shortest disjoint risk groups path pairs between source and + * destination devices. + * + * @param src source device + * @param dst destination device + * @param weight edge weight object + * @param riskProfile map representing risk groups for each edge + * @return set of shortest disjoint paths + */ + private Set disjointPaths(DeviceId src, DeviceId dst, LinkWeight weight, + Map riskProfile) { + DefaultTopologyVertex srcV = new DefaultTopologyVertex(src); + DefaultTopologyVertex dstV = new DefaultTopologyVertex(dst); + + Set vertices = graph.getVertexes(); + if (!vertices.contains(srcV) || !vertices.contains(dstV)) { + // src or dst not part of the current graph + return ImmutableSet.of(); + } + + SRLGGraphSearch srlg = new SRLGGraphSearch<>(riskProfile); + GraphPathSearch.Result result = + srlg.search(graph, srcV, dstV, weight, ALL_PATHS); + ImmutableSet.Builder builder = ImmutableSet.builder(); + for (org.onlab.graph.Path path : result.paths()) { + builder.add(networkDisjointPath((org.onlab.graph.DisjointPathPair) path)); + } + return builder.build(); + } + + /** + * Computes on-demand the set of shortest disjoint risk groups path pairs between source and + * destination devices. + * + * @param src source device + * @param dst destination device + * @param weight edge weight object + * @param riskProfile map representing risk groups for each link + * @return set of shortest disjoint paths + */ + public Set getDisjointPaths(DeviceId src, DeviceId dst, LinkWeight weight, + Map riskProfile) { + Map riskProfile2 = new HashMap<>(); + for (Link l : riskProfile.keySet()) { + riskProfile2.put(new TopologyEdge() { + Link cur = l; + + public Link link() { + return cur; + } + + public TopologyVertex src() { + return () -> src; + } + + public TopologyVertex dst() { + return () -> dst; + } + }, riskProfile.get(l)); + } + return disjointPaths(src, dst, weight, riskProfile2); + } + + /** + * Computes on-demand the set of shortest disjoint risk groups path pairs between source and + * destination devices. + * + * @param src source device + * @param dst destination device + * @param riskProfile map representing risk groups for each link + * @return set of shortest disjoint paths + */ + public Set getDisjointPaths(DeviceId src, DeviceId dst, Map riskProfile) { + return getDisjointPaths(src, dst, null, riskProfile); + } + // Converts graph path to a network path with the same cost. private Path networkPath(org.onlab.graph.Path path) { - List links = new ArrayList<>(); - for (TopologyEdge edge : path.edges()) { - links.add(edge.link()); - } + List links = path.edges().stream().map(TopologyEdge::link).collect(Collectors.toList()); return new DefaultPath(CORE_PROVIDER_ID, links, path.cost()); } + private DisjointPath networkDisjointPath(DisjointPathPair path) { + return new DefaultDisjointPath(CORE_PROVIDER_ID, + (DefaultPath) networkPath(path.primary()), + (DefaultPath) networkPath(path.secondary())); + } + // Searches for SCC clusters in the network topology graph using Tarjan // algorithm. private SCCResult searchForClusters() { @@ -334,6 +463,7 @@ public class DefaultTopology extends AbstractModel implements Topology { private ImmutableMap buildTopologyClusters() { ImmutableMap.Builder clusterBuilder = ImmutableMap.builder(); SCCResult results = clusterResults.get(); + // Extract both vertexes and edges from the results; the lists form // pairs along the same index. List> clusterVertexes = results.clusterVertexes(); diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java index 6bf46803..54e1146b 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java @@ -38,10 +38,8 @@ import org.onosproject.net.flow.criteria.Criterion; import com.fasterxml.jackson.databind.node.ObjectNode; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.onlab.junit.TestUtils.getField; -import static org.onlab.junit.TestUtils.setField; import static org.onosproject.codec.impl.CriterionJsonMatcher.matchesCriterion; /** @@ -429,17 +427,4 @@ public class CriterionCodecTest { ObjectNode result = criterionCodec.encode(criterion, context); assertThat(result, matchesCriterion(criterion)); } - - /** - * Tests that an unimplemented criterion type only returns the type and - * no other data. - */ - @Test - public void matchUnknownTypeTest() throws Exception { - Criterion criterion = Criteria.matchOpticalSignalType((byte) 250); - setField(criterion, "type", Criterion.Type.UNASSIGNED_40); - ObjectNode result = criterionCodec.encode(criterion, context); - assertThat(result.get("type").textValue(), is(criterion.type().toString())); - assertThat(result.size(), is(1)); - } } diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java index 72081e6c..c3cdca0f 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java @@ -416,6 +416,8 @@ public final class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher>> flowEntries = new ConcurrentHashMap<>(); + private final ConcurrentMap> + deviceTableStats = new ConcurrentHashMap<>(); + private final AtomicInteger localBatchIdGen = new AtomicInteger(); // TODO: make this configurable @@ -97,6 +103,7 @@ public class SimpleFlowRuleStore @Deactivate public void deactivate() { + deviceTableStats.clear(); flowEntries.clear(); log.info("Stopped"); } @@ -315,4 +322,20 @@ public class SimpleFlowRuleStore } } } + + @Override + public FlowRuleEvent updateTableStatistics(DeviceId deviceId, + List tableStats) { + deviceTableStats.put(deviceId, tableStats); + return null; + } + + @Override + public Iterable getTableStatistics(DeviceId deviceId) { + List tableStats = deviceTableStats.get(deviceId); + if (tableStats == null) { + return Collections.emptyList(); + } + return ImmutableList.copyOf(tableStats); + } } diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java index 264d0493..72ec98ca 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java @@ -159,6 +159,11 @@ public class SimpleHostStore } } + @Override + public HostEvent removeIp(HostId hostId, IpAddress ipAddress) { + return null; + } + @Override public int getHostCount() { return hosts.size(); diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimplePacketStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimplePacketStore.java index f8359262..7dda12c8 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimplePacketStore.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimplePacketStore.java @@ -15,10 +15,13 @@ */ package org.onosproject.store.trivial; -import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Service; +import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.packet.OutboundPacket; import org.onosproject.net.packet.PacketEvent; import org.onosproject.net.packet.PacketEvent.Type; @@ -27,7 +30,9 @@ import org.onosproject.net.packet.PacketStore; import org.onosproject.net.packet.PacketStoreDelegate; import org.onosproject.store.AbstractStore; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -39,7 +44,7 @@ public class SimplePacketStore extends AbstractStore implements PacketStore { - private Set requests = Sets.newConcurrentHashSet(); + private Map> requests = Maps.newConcurrentMap(); @Override public void emit(OutboundPacket packet) { @@ -47,18 +52,50 @@ public class SimplePacketStore } @Override - public boolean requestPackets(PacketRequest request) { - return requests.add(request); + public void requestPackets(PacketRequest request) { + requests.compute(request.selector(), (s, existingRequests) -> { + if (existingRequests == null) { + return ImmutableSet.of(request); + } else if (!existingRequests.contains(request)) { + if (delegate != null) { + delegate.requestPackets(request); + } + return ImmutableSet.builder() + .addAll(existingRequests) + .add(request) + .build(); + } else { + return existingRequests; + } + }); } @Override - public boolean cancelPackets(PacketRequest request) { - return requests.remove(request); + public void cancelPackets(PacketRequest request) { + requests.computeIfPresent(request.selector(), (s, existingRequests) -> { + if (existingRequests.contains(request)) { + HashSet newRequests = Sets.newHashSet(existingRequests); + newRequests.remove(request); + if (newRequests.size() > 0) { + return ImmutableSet.copyOf(newRequests); + } else { + if (delegate != null) { + delegate.cancelPackets(request); + } + return null; + } + } else { + return existingRequests; + } + }); } @Override public List existingRequests() { - return ImmutableList.copyOf(requests); + List list = Lists.newArrayList(); + requests.values().forEach(list::addAll); + list.sort((o1, o2) -> o1.priority().priorityValue() - o2.priority().priorityValue()); + return list; } } diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java index 6a89c019..29c5d844 100644 --- a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java @@ -23,6 +23,7 @@ import org.onosproject.common.DefaultTopology; import org.onosproject.event.Event; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; +import org.onosproject.net.DisjointPath; import org.onosproject.net.Link; import org.onosproject.net.Path; import org.onosproject.net.provider.ProviderId; @@ -39,6 +40,7 @@ import org.onosproject.store.AbstractStore; import org.slf4j.Logger; import java.util.List; +import java.util.Map; import java.util.Set; import static org.slf4j.LoggerFactory.getLogger; @@ -113,6 +115,29 @@ public class SimpleTopologyStore return defaultTopology(topology).getPaths(src, dst, weight); } + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst) { + return defaultTopology(topology).getDisjointPaths(src, dst); + } + + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight) { + return defaultTopology(topology).getDisjointPaths(src, dst, weight); + } + + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + Map riskProfile) { + return defaultTopology(topology).getDisjointPaths(src, dst, riskProfile); + } + + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight, Map riskProfile) { + return defaultTopology(topology).getDisjointPaths(src, dst, weight, riskProfile); + } + @Override public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) { return defaultTopology(topology).isInfrastructure(connectPoint); diff --git a/framework/src/onos/core/net/pom.xml b/framework/src/onos/core/net/pom.xml index 9ea00070..c5d31263 100644 --- a/framework/src/onos/core/net/pom.xml +++ b/framework/src/onos/core/net/pom.xml @@ -50,6 +50,20 @@ ${project.version} + + org.onosproject + ${project.version} + onos-cli + + + + org.onosproject + onos-cli + ${project.version} + tests + test + + org.onosproject onos-core-common diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigLoader.java b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigLoader.java new file mode 100644 index 00000000..6678db27 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigLoader.java @@ -0,0 +1,74 @@ +/* + * 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.cfg.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onosproject.cfg.ComponentConfigService; +import org.slf4j.Logger; + +import java.io.File; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Component responsible for automatically loading configuration file from + * configuration directory. + */ +@Component(immediate = true) +public class ComponentConfigLoader { + + private static final String CFG_JSON = "../config/component-cfg.json"; + static File cfgFile = new File(CFG_JSON); + + private final Logger log = getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ComponentConfigService configService; + + private ObjectNode root; + + @Activate + protected void activate() { + this.loadConfigs(); + log.info("Started"); + } + + // Loads the configurations for each component from the file in + // ../config/component-cfg.json, using the preSetProperty method. + private void loadConfigs() { + try { + if (cfgFile.exists()) { + root = (ObjectNode) new ObjectMapper().readTree(cfgFile); + root.fieldNames(). + forEachRemaining(component -> root.path(component).fieldNames() + .forEachRemaining(k -> configService + .preSetProperty(component, k, + root.path(component).path(k) + .asText()))); + log.info("Loaded initial component configuration from {}", cfgFile); + } + } catch (Exception e) { + log.warn("Unable to load initial component configuration from {}", + cfgFile, e); + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java index 1933ee55..b3b22c76 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java @@ -61,6 +61,9 @@ public class ComponentConfigManager implements ComponentConfigService { private static final String COMPONENT_NULL = "Component name cannot be null"; private static final String PROPERTY_NULL = "Property name cannot be null"; + private static final String COMPONENT_MISSING = "Component %s is not registered"; + private static final String PROPERTY_MISSING = "Property %s does not exist for %s"; + //Symbolic constants for use with the accumulator private static final int MAX_ITEMS = 100; @@ -160,6 +163,22 @@ public class ComponentConfigManager implements ComponentConfigService { checkNotNull(componentName, COMPONENT_NULL); checkNotNull(name, PROPERTY_NULL); + + checkArgument(properties.containsKey(componentName), + COMPONENT_MISSING, componentName); + checkArgument(properties.get(componentName).containsKey(name), + PROPERTY_MISSING, name, componentName); + store.setProperty(componentName, name, value); + } + + @Override + public void preSetProperty(String componentName, String name, String value) { + + checkPermission(CONFIG_WRITE); + + checkNotNull(componentName, COMPONENT_NULL); + checkNotNull(name, PROPERTY_NULL); + store.setProperty(componentName, name, value); } @@ -169,6 +188,11 @@ public class ComponentConfigManager implements ComponentConfigService { checkNotNull(componentName, COMPONENT_NULL); checkNotNull(name, PROPERTY_NULL); + + checkArgument(properties.containsKey(componentName), + COMPONENT_MISSING, componentName); + checkArgument(properties.get(componentName).containsKey(name), + PROPERTY_MISSING, name, componentName); store.unsetProperty(componentName, name); } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/CoreManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/CoreManager.java index 8a441f61..f4d560a4 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/CoreManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/CoreManager.java @@ -24,7 +24,6 @@ import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; import org.onlab.util.SharedExecutors; -import org.onlab.util.Tools; import org.onosproject.cfg.ComponentConfigService; import org.onosproject.core.ApplicationId; import org.onosproject.core.ApplicationIdStore; @@ -38,6 +37,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Dictionary; import java.util.List; import java.util.Set; @@ -87,9 +90,15 @@ public class CoreManager implements CoreService { public void activate() { registerApplication(CORE_APP_NAME); cfgService.registerProperties(getClass()); - List versionLines = Tools.slurp(VERSION_FILE); - if (versionLines != null && !versionLines.isEmpty()) { - version = Version.version(versionLines.get(0)); + try { + Path path = Paths.get(VERSION_FILE.getPath()); + List versionLines = Files.readAllLines(path); + if (versionLines != null && !versionLines.isEmpty()) { + version = Version.version(versionLines.get(0)); + } + } catch (IOException e) { + // version file not found, using default + log.trace("Version file not found", e); } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java index 5cd96cab..db484eea 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java @@ -96,7 +96,7 @@ public class NetworkConfigManager configClasses.put(identifier(configFactory), configFactory.configClass()); SubjectFactory subjectFactory = configFactory.subjectFactory(); - subjectClasses.putIfAbsent(subjectFactory.subjectKey(), subjectFactory); + subjectClasses.putIfAbsent(subjectFactory.subjectClassKey(), subjectFactory); subjectClassKeys.putIfAbsent(subjectFactory.subjectClass(), subjectFactory); store.addConfigFactory(configFactory); @@ -145,8 +145,8 @@ public class NetworkConfigManager } @Override - public SubjectFactory getSubjectFactory(String subjectKey) { - return subjectClasses.get(subjectKey); + public SubjectFactory getSubjectFactory(String subjectClassKey) { + return subjectClasses.get(subjectClassKey); } @Override @@ -155,8 +155,8 @@ public class NetworkConfigManager } @Override - public Class getConfigClass(String subjectKey, String configKey) { - return configClasses.get(new ConfigIdentifier(subjectKey, configKey)); + public Class getConfigClass(String subjectClassKey, String configKey) { + return configClasses.get(new ConfigIdentifier(subjectClassKey, configKey)); } @Override @@ -255,7 +255,7 @@ public class NetworkConfigManager } private static ConfigIdentifier identifier(ConfigFactory factory) { - return new ConfigIdentifier(factory.subjectFactory().subjectKey(), factory.configKey()); + return new ConfigIdentifier(factory.subjectFactory().subjectClassKey(), factory.configKey()); } static final class ConfigIdentifier { diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/BasicDeviceOperator.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/BasicDeviceOperator.java index 7900d185..fa90eb65 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/BasicDeviceOperator.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/BasicDeviceOperator.java @@ -15,21 +15,21 @@ */ package org.onosproject.net.device.impl; -import static org.slf4j.LoggerFactory.getLogger; -import static com.google.common.base.Preconditions.checkNotNull; - -import org.onosproject.net.config.ConfigOperator; -import org.onosproject.net.config.basics.BasicDeviceConfig; import org.onosproject.net.AnnotationKeys; import org.onosproject.net.DefaultAnnotations; import org.onosproject.net.Device; import org.onosproject.net.SparseAnnotations; +import org.onosproject.net.config.ConfigOperator; +import org.onosproject.net.config.basics.BasicDeviceConfig; import org.onosproject.net.device.DefaultDeviceDescription; import org.onosproject.net.device.DeviceDescription; import org.slf4j.Logger; import java.util.Objects; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.slf4j.LoggerFactory.getLogger; + /** * Implementations of merge policies for various sources of device configuration * information. This includes applications, provides, and network configurations. @@ -46,7 +46,7 @@ public final class BasicDeviceOperator implements ConfigOperator { * Generates a DeviceDescription containing fields from a DeviceDescription and * a DeviceConfig. * - * @param bdc the device config entity from network config + * @param bdc the device config entity from network config * @param descr a DeviceDescription * @return DeviceDescription based on both sources */ @@ -70,7 +70,7 @@ public final class BasicDeviceOperator implements ConfigOperator { * Generates an annotation from an existing annotation and DeviceConfig. * * @param bdc the device config entity from network config - * @param an the annotation + * @param an the annotation * @return annotation combining both sources */ public static SparseAnnotations combine(BasicDeviceConfig bdc, SparseAnnotations an) { @@ -93,6 +93,9 @@ public final class BasicDeviceOperator implements ConfigOperator { if (bdc.owner() != null) { newBuilder.set(AnnotationKeys.OWNER, bdc.owner()); } + if (bdc.managementAddress() != null) { + newBuilder.set(AnnotationKeys.MANAGEMENT_ADDRESS, bdc.managementAddress()); + } DefaultAnnotations newAnnotations = newBuilder.build(); return DefaultAnnotations.union(an, newAnnotations); } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java index b0b3abe2..e35dc0c5 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java @@ -15,8 +15,26 @@ */ package org.onosproject.net.device.impl; -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.Futures; +import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; +import static org.onlab.util.Tools.groupedThreads; +import static org.onosproject.net.MastershipRole.MASTER; +import static org.onosproject.net.MastershipRole.NONE; +import static org.onosproject.net.MastershipRole.STANDBY; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.onosproject.security.AppPermission.Type.DEVICE_READ; +import static org.slf4j.LoggerFactory.getLogger; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; @@ -26,12 +44,6 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; import org.onosproject.cluster.ClusterService; import org.onosproject.cluster.NodeId; -import org.onosproject.net.provider.AbstractListenerProviderRegistry; -import org.onosproject.net.config.NetworkConfigEvent; -import org.onosproject.net.config.NetworkConfigListener; -import org.onosproject.net.config.NetworkConfigService; -import org.onosproject.net.config.basics.BasicDeviceConfig; -import org.onosproject.net.config.basics.OpticalPortConfig; import org.onosproject.mastership.MastershipEvent; import org.onosproject.mastership.MastershipListener; import org.onosproject.mastership.MastershipService; @@ -44,6 +56,11 @@ import org.onosproject.net.DeviceId; import org.onosproject.net.MastershipRole; import org.onosproject.net.Port; import org.onosproject.net.PortNumber; +import org.onosproject.net.config.NetworkConfigEvent; +import org.onosproject.net.config.NetworkConfigListener; +import org.onosproject.net.config.NetworkConfigService; +import org.onosproject.net.config.basics.BasicDeviceConfig; +import org.onosproject.net.config.basics.OpticalPortConfig; import org.onosproject.net.device.DefaultDeviceDescription; import org.onosproject.net.device.DefaultPortDescription; import org.onosproject.net.device.DeviceAdminService; @@ -58,27 +75,11 @@ import org.onosproject.net.device.DeviceStore; import org.onosproject.net.device.DeviceStoreDelegate; import org.onosproject.net.device.PortDescription; import org.onosproject.net.device.PortStatistics; +import org.onosproject.net.provider.AbstractListenerProviderRegistry; import org.onosproject.net.provider.AbstractProviderService; import org.slf4j.Logger; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import static com.google.common.base.Preconditions.checkNotNull; -import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; -import static org.onlab.util.Tools.groupedThreads; -import static org.onosproject.net.MastershipRole.*; -import static org.onosproject.security.AppGuard.checkPermission; -import static org.slf4j.LoggerFactory.getLogger; -import static org.onosproject.security.AppPermission.Type.*; +import com.google.common.util.concurrent.Futures; /** * Provides implementation of the device SB & NB APIs. @@ -347,11 +348,15 @@ public class DeviceManager log.info("Device {} disconnected from this node", deviceId); List ports = store.getPorts(deviceId); - List descs = Lists.newArrayList(); - ports.forEach(port -> - descs.add(new DefaultPortDescription(port.number(), - false, port.type(), - port.portSpeed()))); + final Device device = getDevice(deviceId); + + List descs = ports.stream().map( + port -> (!(Device.Type.ROADM.equals(device.type()))) ? + new DefaultPortDescription(port.number(), false, + port.type(), port.portSpeed()) : + OpticalPortOperator.descriptionOf(port, false) + ).collect(Collectors.toList()); + store.updatePorts(this.provider().id(), deviceId, descs); try { if (mastershipService.isLocalMaster(deviceId)) { @@ -430,6 +435,12 @@ public class DeviceManager portDescription); return; } + final Device device = getDevice(deviceId); + if ((Device.Type.ROADM.equals(device.type()))) { + Port port = getPort(deviceId, portDescription.portNumber()); + portDescription = OpticalPortOperator.descriptionOf(port, portDescription.isEnabled()); + } + portDescription = consolidate(deviceId, portDescription); final DeviceEvent event = store.updatePortStatus(this.provider().id(), deviceId, portDescription); diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java index b2fd02c7..8f2bda01 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java @@ -151,8 +151,25 @@ public final class OpticalPortOperator implements ConfigOperator { */ public static PortDescription descriptionOf(Port port) { checkNotNull(port, "Must supply non-null Port"); + final boolean isUp = port.isEnabled(); + return descriptionOfPort(port, isUp); + } + + /** + * Returns a description built from an existing port and reported status. + * + * @param port + * @param isEnabled + * @return a PortDescription based on the port + */ + static PortDescription descriptionOf(Port port, boolean isEnabled) { + checkNotNull(port, "Must supply non-null Port"); + final boolean isup = isEnabled; + return descriptionOfPort(port, isup); + } + + private static PortDescription descriptionOfPort(Port port, final boolean isup) { final PortNumber ptn = port.number(); - final boolean isup = port.isEnabled(); final SparseAnnotations an = (SparseAnnotations) port.annotations(); switch (port.type()) { case OMS: diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java index a1d046c5..5958d1f5 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java @@ -22,6 +22,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; + import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -58,6 +59,7 @@ import org.onosproject.net.flow.FlowRuleProviderService; import org.onosproject.net.flow.FlowRuleService; import org.onosproject.net.flow.FlowRuleStore; import org.onosproject.net.flow.FlowRuleStoreDelegate; +import org.onosproject.net.flow.TableStatisticsEntry; import org.onosproject.net.provider.AbstractProviderService; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; @@ -388,6 +390,16 @@ public class FlowRuleManager @Override public void pushFlowMetrics(DeviceId deviceId, Iterable flowEntries) { + pushFlowMetricsInternal(deviceId, flowEntries, true); + } + + @Override + public void pushFlowMetricsWithoutFlowMissing(DeviceId deviceId, Iterable flowEntries) { + pushFlowMetricsInternal(deviceId, flowEntries, false); + } + + private void pushFlowMetricsInternal(DeviceId deviceId, Iterable flowEntries, + boolean useMissingFlow) { Map storedRules = Maps.newHashMap(); store.getFlowEntries(deviceId).forEach(f -> storedRules.put(f, f)); @@ -415,17 +427,20 @@ public class FlowRuleManager continue; } } - for (FlowEntry rule : storedRules.keySet()) { - try { - // there are rules in the store that aren't on the switch - log.debug("Adding rule in store, but not on switch {}", rule); - flowMissing(rule); - } catch (Exception e) { - log.debug("Can't add missing flow rule {}", e.getMessage()); - continue; + + // DO NOT reinstall + if (useMissingFlow) { + for (FlowEntry rule : storedRules.keySet()) { + try { + // there are rules in the store that aren't on the switch + log.debug("Adding rule in store, but not on switch {}", rule); + flowMissing(rule); + } catch (Exception e) { + log.debug("Can't add missing flow rule {}", e.getMessage()); + continue; + } } } - } @Override @@ -435,6 +450,12 @@ public class FlowRuleManager operation )); } + + @Override + public void pushTableStatistics(DeviceId deviceId, + List tableStats) { + store.updateTableStatistics(deviceId, tableStats); + } } // Store delegate to re-post events emitted from the store. @@ -590,4 +611,10 @@ public class FlowRuleManager } } + + @Override + public Iterable getFlowTableStatistics(DeviceId deviceId) { + checkPermission(FLOWRULE_READ); + return store.getTableStatistics(deviceId); + } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java index 43f346b7..1473f33f 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java @@ -236,6 +236,16 @@ public class HostManager post(event); } } + + @Override + public void removeIpFromHost(HostId hostId, IpAddress ipAddress) { + checkNotNull(hostId, HOST_ID_NULL); + checkValidity(); + HostEvent event = store.removeIp(hostId, ipAddress); + if (event != null) { + post(event); + } + } } // Store delegate to re-post events emitted from the store. diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java index 44f8cbf0..4dc93a51 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java @@ -84,6 +84,7 @@ public class HostMonitor implements TimerTask { * @param hostManager host manager used to look up host information and * probe existing hosts * @param interfaceService interface service for interface information + * @param edgePortService edge port service */ public HostMonitor(PacketService packetService, HostManager hostManager, InterfaceService interfaceService, diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java index d7fa3223..417627ad 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java @@ -196,7 +196,7 @@ public class IntentCleanup implements Runnable, IntentListener { service.withdraw(intentData.intent()); break; default: - log.warn("Trying to resubmit pending intent {} in state {} with request {}", + log.warn("Failed to resubmit pending intent {} in state {} with request {}", intentData.key(), intentData.state(), intentData.request()); break; } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java index 4c828e77..baa3bf4d 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java @@ -256,15 +256,16 @@ public class IntentManager submit(intent); } - // If required, compile all currently failed intents. - for (Intent intent : getIntents()) { - IntentState state = getIntentState(intent.key()); - if ((compileAllFailed && RECOMPILE.contains(state)) - || intentAllowsPartialFailure(intent)) { - if (WITHDRAW.contains(state)) { - withdraw(intent); - } else { - submit(intent); + if (compileAllFailed) { + // If required, compile all currently failed intents. + for (Intent intent : getIntents()) { + IntentState state = getIntentState(intent.key()); + if (RECOMPILE.contains(state) || intentAllowsPartialFailure(intent)) { + if (WITHDRAW.contains(state)) { + withdraw(intent); + } else { + submit(intent); + } } } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTracker.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTracker.java index 5710aced..5ebc812e 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTracker.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTracker.java @@ -16,8 +16,8 @@ package org.onosproject.net.intent.impl; import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.google.common.collect.SetMultimap; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; @@ -61,7 +61,6 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -91,8 +90,6 @@ public class ObjectiveTracker implements ObjectiveTrackerService { private final Logger log = getLogger(getClass()); - private final ConcurrentMap intents = Maps.newConcurrentMap(); - private final SetMultimap intentsByLink = //TODO this could be slow as a point of synchronization synchronizedSetMultimap(HashMultimap.create()); @@ -378,7 +375,12 @@ public class ObjectiveTracker implements ObjectiveTrackerService { } // TODO should we recompile on available==true? - delegate.triggerCompile(intentsByDevice.get(id), available); + + final ImmutableSet snapshot; + synchronized (intentsByDevice) { + snapshot = ImmutableSet.copyOf(intentsByDevice.get(id)); + } + delegate.triggerCompile(snapshot, available); } } @@ -415,9 +417,17 @@ public class ObjectiveTracker implements ObjectiveTrackerService { @Override public void event(HostEvent event) { HostId id = event.subject().id(); - HostEvent.Type type = event.type(); - boolean available = (type == HostEvent.Type.HOST_ADDED); - executorService.execute(new DeviceAvailabilityHandler(id, available)); + switch (event.type()) { + case HOST_ADDED: + case HOST_MOVED: + case HOST_REMOVED: + executorService.execute(new DeviceAvailabilityHandler(id, false)); + break; + case HOST_UPDATED: + default: + // DO NOTHING + break; + } } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java index 99f58df7..c6eb7c5a 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java @@ -15,10 +15,8 @@ */ package org.onosproject.net.intent.impl.compiler; -import com.google.common.collect.Sets; import org.apache.commons.lang3.tuple.Pair; import org.apache.felix.scr.annotations.Activate; -import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Modified; import org.apache.felix.scr.annotations.Property; @@ -50,7 +48,10 @@ import org.onosproject.net.intent.IntentService; import org.onosproject.net.intent.OpticalCircuitIntent; import org.onosproject.net.intent.OpticalConnectivityIntent; import org.onosproject.net.intent.impl.IntentCompilationException; -import org.onosproject.net.resource.device.DeviceResourceService; +import org.onosproject.net.newresource.ResourceAllocation; +import org.onosproject.net.newresource.ResourcePath; +import org.onosproject.net.newresource.ResourceService; +import org.onosproject.net.resource.device.IntentSetMultimap; import org.onosproject.net.resource.link.LinkResourceAllocations; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; @@ -60,6 +61,7 @@ import java.util.Collections; import java.util.Dictionary; import java.util.LinkedList; import java.util.List; +import java.util.Optional; import java.util.Set; import static com.google.common.base.Preconditions.checkArgument; @@ -67,7 +69,8 @@ import static com.google.common.base.Preconditions.checkArgument; /** * An intent compiler for {@link org.onosproject.net.intent.OpticalCircuitIntent}. */ -@Component(immediate = true) +// For now, remove component designation until dependency on the new resource manager is available. +// @Component(immediate = true) public class OpticalCircuitIntentCompiler implements IntentCompiler { private static final Logger log = LoggerFactory.getLogger(OpticalCircuitIntentCompiler.class); @@ -92,7 +95,10 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler allocation = resourceService.allocate(intent.id(), srcPortPath, dstPortPath); + if (allocation.isEmpty()) { throw new IntentCompilationException("Unable to reserve ports for intent " + intent); } @@ -199,7 +208,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler mapping = deviceResourceService.getMapping(resource); + Set mapping = intentSetMultimap.getMapping(resource); if (mapping == null) { return true; @@ -271,7 +279,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler intentId = + resourceService.getResourceAllocation(new ResourcePath(ochCP.deviceId(), ochCP.port())) + .map(ResourceAllocation::consumer) + .filter(x -> x instanceof IntentId) + .map(x -> (IntentId) x); + + if (isAvailable(intentId.orElse(null))) { return ochPort; } } @@ -316,8 +329,12 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler intentId = + resourceService.getResourceAllocation(new ResourcePath(oduPort.deviceId(), port.number())) + .map(ResourceAllocation::consumer) + .filter(x -> x instanceof IntentId) + .map(x -> (IntentId) x); + if (isAvailable(intentId.orElse(null))) { return (OchPort) port; } } @@ -327,12 +344,12 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler findPorts(OpticalCircuitIntent intent) { - OchPort srcPort = findAvailableOchPort(intent.getSrc(), intent); + OchPort srcPort = findAvailableOchPort(intent.getSrc()); if (srcPort == null) { return null; } - OchPort dstPort = findAvailableOchPort(intent.getDst(), intent); + OchPort dstPort = findAvailableOchPort(intent.getDst()); if (dstPort == null) { return null; } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java index 05a20f96..eb5b4af8 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java @@ -16,9 +16,7 @@ package org.onosproject.net.intent.impl.compiler; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; import org.apache.felix.scr.annotations.Activate; -import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; @@ -40,9 +38,9 @@ import org.onosproject.net.intent.IntentExtensionService; import org.onosproject.net.intent.OpticalConnectivityIntent; import org.onosproject.net.intent.OpticalPathIntent; import org.onosproject.net.intent.impl.IntentCompilationException; -import org.onosproject.net.resource.ResourceAllocation; +import org.onosproject.net.newresource.ResourcePath; +import org.onosproject.net.newresource.ResourceService; import org.onosproject.net.resource.ResourceType; -import org.onosproject.net.resource.device.DeviceResourceService; import org.onosproject.net.resource.link.DefaultLinkResourceRequest; import org.onosproject.net.resource.link.LambdaResource; import org.onosproject.net.resource.link.LambdaResourceAllocation; @@ -57,13 +55,15 @@ import org.slf4j.LoggerFactory; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkArgument; /** * An intent compiler for {@link org.onosproject.net.intent.OpticalConnectivityIntent}. */ -@Component(immediate = true) +// For now, remove component designation until dependency on the new resource manager is available. +// @Component(immediate = true) public class OpticalConnectivityIntentCompiler implements IntentCompiler { protected static final Logger log = LoggerFactory.getLogger(OpticalConnectivityIntentCompiler.class); @@ -78,10 +78,10 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler allocation = + resourceService.allocate(intent.id(), srcPortPath, dstPortPath); + if (allocation.isEmpty()) { throw new IntentCompilationException("Unable to reserve ports for intent " + intent); } @@ -161,7 +165,7 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler linkAllocs.getResourceAllocation(x).stream()) + .filter(x -> x.type() == ResourceType.LAMBDA) + .findFirst() + .map(x -> (LambdaResourceAllocation) x) + .orElse(null); } /** @@ -215,23 +216,23 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler lambdas = path.links().stream() + .flatMap(x -> allocations.getResourceAllocation(x).stream()) + .filter(x -> x.type() == ResourceType.LAMBDA) + .map(x -> ((LambdaResourceAllocation) x).lambda()) + .collect(Collectors.toList()); - for (Link link : path.links()) { - for (ResourceAllocation alloc : allocations.getResourceAllocation(link)) { - if (alloc.type() == ResourceType.LAMBDA) { - LambdaResource nextLambda = ((LambdaResourceAllocation) alloc).lambda(); - if (nextLambda == null) { - return false; - } - if (lambda == null) { - lambda = nextLambda; - continue; - } - if (!lambda.equals(nextLambda)) { - return false; - } - } + LambdaResource lambda = null; + for (LambdaResource nextLambda: lambdas) { + if (nextLambda == null) { + return false; + } + if (lambda == null) { + lambda = nextLambda; + continue; + } + if (!lambda.equals(nextLambda)) { + return false; } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java index ca9ae5cc..2cc45e79 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java @@ -39,7 +39,6 @@ import org.onosproject.net.intent.IntentCompiler; import org.onosproject.net.intent.IntentExtensionService; import org.onosproject.net.intent.OpticalPathIntent; import org.onosproject.net.resource.link.LinkResourceAllocations; -import org.onosproject.net.resource.link.LinkResourceService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,9 +58,6 @@ public class OpticalPathIntentCompiler implements IntentCompiler getResourceAllocation(ResourcePath resource) { + checkNotNull(resource); + + Optional consumer = store.getConsumer(resource); + return consumer.map(x -> new ResourceAllocation(resource, x)); + } + @Override public Collection getResourceAllocations(ResourcePath parent, Class cls) { checkNotNull(parent); diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java index a0bc693c..8e87a07d 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java @@ -15,7 +15,8 @@ */ package org.onosproject.net.packet.impl; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -43,6 +44,7 @@ import org.onosproject.net.packet.PacketContext; import org.onosproject.net.packet.PacketEvent; import org.onosproject.net.packet.PacketPriority; import org.onosproject.net.packet.PacketProcessor; +import org.onosproject.net.packet.PacketProcessorEntry; import org.onosproject.net.packet.PacketProvider; import org.onosproject.net.packet.PacketProviderRegistry; import org.onosproject.net.packet.PacketProviderService; @@ -55,8 +57,6 @@ import org.onosproject.net.provider.AbstractProviderService; import org.slf4j.Logger; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -102,18 +102,18 @@ public class PacketManager private final DeviceListener deviceListener = new InternalDeviceListener(); - private final Map processors = new ConcurrentHashMap<>(); + private final List processors = Lists.newCopyOnWriteArrayList(); private ApplicationId appId; @Activate public void activate() { eventHandlingExecutor = Executors.newSingleThreadExecutor( - groupedThreads("onos/net/packet", "event-handler")); + groupedThreads("onos/net/packet", "event-handler")); appId = coreService.getAppId(CoreService.CORE_APP_NAME); store.setDelegate(delegate); deviceService.addListener(deviceListener); - // TODO: Should we request packets for all existing devices? I believe we should. + store.existingRequests().forEach(this::pushToAllDevices); log.info("Started"); } @@ -129,19 +129,35 @@ public class PacketManager public void addProcessor(PacketProcessor processor, int priority) { checkPermission(PACKET_EVENT); checkNotNull(processor, "Processor cannot be null"); - processors.put(priority, processor); + ProcessorEntry entry = new ProcessorEntry(processor, priority); + + // Insert the new processor according to its priority. + int i = 0; + for (; i < processors.size(); i++) { + if (priority < processors.get(i).priority()) { + break; + } + } + processors.add(i, entry); } @Override public void removeProcessor(PacketProcessor processor) { checkPermission(PACKET_EVENT); checkNotNull(processor, "Processor cannot be null"); - processors.values().remove(processor); + + // Remove the processor entry. + for (int i = 0; i < processors.size(); i++) { + if (processors.get(i).processor() == processor) { + processors.remove(i); + break; + } + } } @Override - public Map getProcessors() { - return ImmutableMap.copyOf(processors); + public List getProcessors() { + return ImmutableList.copyOf(processors); } @Override @@ -152,9 +168,7 @@ public class PacketManager checkNotNull(appId, "Application ID cannot be null"); PacketRequest request = new DefaultPacketRequest(selector, priority, appId); - if (store.requestPackets(request)) { - pushToAllDevices(request); - } + store.requestPackets(request); } @Override @@ -165,9 +179,7 @@ public class PacketManager checkNotNull(appId, "Application ID cannot be null"); PacketRequest request = new DefaultPacketRequest(selector, priority, appId); - if (store.cancelPackets(request)) { - removeFromAllDevices(request); - } + store.cancelPackets(request); } @Override @@ -175,6 +187,18 @@ public class PacketManager return store.existingRequests(); } + /** + * Pushes all rules to the specified device. + * + * @param device device on which to install packet request flows + */ + private void pushRulesToDevice(Device device) { + log.debug("Pushing packet requests to device {}", device.id()); + for (PacketRequest request : store.existingRequests()) { + pushRule(device, request); + } + } + /** * Pushes a packet request flow rule to all devices. * @@ -187,16 +211,13 @@ public class PacketManager } } - /** * Removes packet request flow rule from all devices. * * @param request the packet request */ private void removeFromAllDevices(PacketRequest request) { - for (Device device : deviceService.getDevices()) { - removeRule(device, request); - } + deviceService.getAvailableDevices().forEach(d -> removeRule(d, request)); } /** @@ -232,7 +253,6 @@ public class PacketManager if (!device.type().equals(Device.Type.SWITCH)) { return; } - ForwardingObjective forwarding = createBuilder(request) .remove(new ObjectiveContext() { @Override @@ -241,7 +261,6 @@ public class PacketManager request, device.id(), error); } }); - objectiveService.forward(device.id(), forwarding); } @@ -263,12 +282,10 @@ public class PacketManager } private void localEmit(OutboundPacket packet) { - final Device device = deviceService.getDevice(packet.sendThrough()); - + Device device = deviceService.getDevice(packet.sendThrough()); if (device == null) { return; } - PacketProvider packetProvider = getProvider(device.providerId()); if (packetProvider != null) { packetProvider.emit(packet); @@ -280,7 +297,9 @@ public class PacketManager return new InternalPacketProviderService(provider); } - // Personalized packet provider service issued to the supplied provider. + /** + * Personalized packet provider service issued to the supplied provider. + */ private class InternalPacketProviderService extends AbstractProviderService implements PacketProviderService { @@ -292,8 +311,10 @@ public class PacketManager @Override public void processPacket(PacketContext context) { // TODO filter packets sent to processors based on registrations - for (PacketProcessor processor : processors.values()) { - processor.process(context); + for (ProcessorEntry entry : processors) { + long start = System.nanoTime(); + entry.processor().process(context); + entry.addNanos(System.nanoTime() - start); } } @@ -307,6 +328,16 @@ public class PacketManager public void notify(PacketEvent event) { localEmit(event.subject()); } + + @Override + public void requestPackets(PacketRequest request) { + pushToAllDevices(request); + } + + @Override + public void cancelPackets(PacketRequest request) { + removeFromAllDevices(request); + } } /** @@ -319,17 +350,14 @@ public class PacketManager try { Device device = event.subject(); switch (event.type()) { - case DEVICE_ADDED: - case DEVICE_AVAILABILITY_CHANGED: - if (deviceService.isAvailable(event.subject().id())) { - log.debug("Pushing packet requests to device {}", event.subject().id()); - for (PacketRequest request : store.existingRequests()) { - pushRule(device, request); + case DEVICE_ADDED: + case DEVICE_AVAILABILITY_CHANGED: + if (deviceService.isAvailable(event.subject().id())) { + pushRulesToDevice(device); } - } - break; - default: - break; + break; + default: + break; } } catch (Exception e) { log.warn("Failed to process {}", event, e); @@ -338,4 +366,48 @@ public class PacketManager } } + /** + * Entity for tracking stats for a packet processor. + */ + private class ProcessorEntry implements PacketProcessorEntry { + private final PacketProcessor processor; + private final int priority; + private long invocations = 0; + private long nanos = 0; + + public ProcessorEntry(PacketProcessor processor, int priority) { + this.processor = processor; + this.priority = priority; + } + + @Override + public PacketProcessor processor() { + return processor; + } + + @Override + public int priority() { + return priority; + } + + @Override + public long invocations() { + return invocations; + } + + @Override + public long totalNanos() { + return nanos; + } + + @Override + public long averageNanos() { + return invocations > 0 ? nanos / invocations : 0; + } + + void addNanos(long nanos) { + this.nanos += nanos; + this.invocations++; + } + } } diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/FlowStatisticManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/FlowStatisticManager.java new file mode 100644 index 00000000..6515ef31 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/FlowStatisticManager.java @@ -0,0 +1,634 @@ +/* + * 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.net.statistic.impl; + +import com.google.common.base.MoreObjects; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableSet; +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; +import org.onosproject.cli.Comparators; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Device; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.flow.DefaultTypedFlowEntry; +import org.onosproject.net.flow.FlowEntry; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.FlowRuleEvent; +import org.onosproject.net.flow.FlowRuleListener; +import org.onosproject.net.flow.FlowRuleService; +import org.onosproject.net.flow.TypedStoredFlowEntry; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.statistic.DefaultLoad; +import org.onosproject.net.statistic.FlowStatisticService; +import org.onosproject.net.statistic.Load; +import org.onosproject.net.statistic.FlowStatisticStore; +import org.onosproject.net.statistic.SummaryFlowEntryWithLoad; +import org.onosproject.net.statistic.TypedFlowEntryWithLoad; + +import org.slf4j.Logger; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeMap; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.slf4j.LoggerFactory.getLogger; +import static org.onosproject.security.AppPermission.Type.*; + +/** + * Provides an implementation of the Flow Statistic Service. + */ +@Component(immediate = true, enabled = true) +@Service +public class FlowStatisticManager implements FlowStatisticService { + private final Logger log = getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected FlowRuleService flowRuleService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected FlowStatisticStore flowStatisticStore; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + private final InternalFlowRuleStatsListener frListener = new InternalFlowRuleStatsListener(); + + @Activate + public void activate() { + flowRuleService.addListener(frListener); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + flowRuleService.removeListener(frListener); + log.info("Stopped"); + } + + @Override + public Map loadSummary(Device device) { + checkPermission(STATISTIC_READ); + + Map summaryLoad = new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR); + + if (device == null) { + return summaryLoad; + } + + List ports = new ArrayList<>(deviceService.getPorts(device.id())); + + for (Port port : ports) { + ConnectPoint cp = new ConnectPoint(device.id(), port.number()); + SummaryFlowEntryWithLoad sfe = loadSummaryPortInternal(cp); + summaryLoad.put(cp, sfe); + } + + return summaryLoad; + } + + @Override + public SummaryFlowEntryWithLoad loadSummary(Device device, PortNumber pNumber) { + checkPermission(STATISTIC_READ); + + ConnectPoint cp = new ConnectPoint(device.id(), pNumber); + return loadSummaryPortInternal(cp); + } + + @Override + public Map> loadAllByType(Device device, + TypedStoredFlowEntry.FlowLiveType liveType, + Instruction.Type instType) { + checkPermission(STATISTIC_READ); + + Map> allLoad = new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR); + + if (device == null) { + return allLoad; + } + + List ports = new ArrayList<>(deviceService.getPorts(device.id())); + + for (Port port : ports) { + ConnectPoint cp = new ConnectPoint(device.id(), port.number()); + List tfel = loadAllPortInternal(cp, liveType, instType); + allLoad.put(cp, tfel); + } + + return allLoad; + } + + @Override + public List loadAllByType(Device device, PortNumber pNumber, + TypedStoredFlowEntry.FlowLiveType liveType, + Instruction.Type instType) { + checkPermission(STATISTIC_READ); + + ConnectPoint cp = new ConnectPoint(device.id(), pNumber); + return loadAllPortInternal(cp, liveType, instType); + } + + @Override + public Map> loadTopnByType(Device device, + TypedStoredFlowEntry.FlowLiveType liveType, + Instruction.Type instType, + int topn) { + checkPermission(STATISTIC_READ); + + Map> allLoad = new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR); + + if (device == null) { + return allLoad; + } + + List ports = new ArrayList<>(deviceService.getPorts(device.id())); + + for (Port port : ports) { + ConnectPoint cp = new ConnectPoint(device.id(), port.number()); + List tfel = loadTopnPortInternal(cp, liveType, instType, topn); + allLoad.put(cp, tfel); + } + + return allLoad; + } + + @Override + public List loadTopnByType(Device device, PortNumber pNumber, + TypedStoredFlowEntry.FlowLiveType liveType, + Instruction.Type instType, + int topn) { + checkPermission(STATISTIC_READ); + + ConnectPoint cp = new ConnectPoint(device.id(), pNumber); + return loadTopnPortInternal(cp, liveType, instType, topn); + } + + private SummaryFlowEntryWithLoad loadSummaryPortInternal(ConnectPoint cp) { + checkPermission(STATISTIC_READ); + + Set currentStats; + Set previousStats; + + TypedStatistics typedStatistics; + synchronized (flowStatisticStore) { + currentStats = flowStatisticStore.getCurrentFlowStatistic(cp); + if (currentStats == null) { + return new SummaryFlowEntryWithLoad(cp, new DefaultLoad()); + } + previousStats = flowStatisticStore.getPreviousFlowStatistic(cp); + if (previousStats == null) { + return new SummaryFlowEntryWithLoad(cp, new DefaultLoad()); + } + // copy to local flow entry + typedStatistics = new TypedStatistics(currentStats, previousStats); + + // Check for validity of this stats data + checkLoadValidity(currentStats, previousStats); + } + + // current and previous set is not empty! + Set currentSet = typedStatistics.current(); + Set previousSet = typedStatistics.previous(); + Load totalLoad = new DefaultLoad(aggregateBytesSet(currentSet), aggregateBytesSet(previousSet), + TypedFlowEntryWithLoad.avgPollInterval()); + + Map currentMap; + Map previousMap; + + currentMap = typedStatistics.currentImmediate(); + previousMap = typedStatistics.previousImmediate(); + Load immediateLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap), + TypedFlowEntryWithLoad.shortPollInterval()); + + currentMap = typedStatistics.currentShort(); + previousMap = typedStatistics.previousShort(); + Load shortLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap), + TypedFlowEntryWithLoad.shortPollInterval()); + + currentMap = typedStatistics.currentMid(); + previousMap = typedStatistics.previousMid(); + Load midLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap), + TypedFlowEntryWithLoad.midPollInterval()); + + currentMap = typedStatistics.currentLong(); + previousMap = typedStatistics.previousLong(); + Load longLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap), + TypedFlowEntryWithLoad.longPollInterval()); + + currentMap = typedStatistics.currentUnknown(); + previousMap = typedStatistics.previousUnknown(); + Load unknownLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap), + TypedFlowEntryWithLoad.avgPollInterval()); + + return new SummaryFlowEntryWithLoad(cp, totalLoad, immediateLoad, shortLoad, midLoad, longLoad, unknownLoad); + } + + private List loadAllPortInternal(ConnectPoint cp, + TypedStoredFlowEntry.FlowLiveType liveType, + Instruction.Type instType) { + checkPermission(STATISTIC_READ); + + List retTFEL = new ArrayList<>(); + + Set currentStats; + Set previousStats; + + TypedStatistics typedStatistics; + synchronized (flowStatisticStore) { + currentStats = flowStatisticStore.getCurrentFlowStatistic(cp); + if (currentStats == null) { + return retTFEL; + } + previousStats = flowStatisticStore.getPreviousFlowStatistic(cp); + if (previousStats == null) { + return retTFEL; + } + // copy to local flow entry set + typedStatistics = new TypedStatistics(currentStats, previousStats); + + // Check for validity of this stats data + checkLoadValidity(currentStats, previousStats); + } + + // current and previous set is not empty! + boolean isAllLiveType = (liveType == null ? true : false); // null is all live type + boolean isAllInstType = (instType == null ? true : false); // null is all inst type + + Map currentMap; + Map previousMap; + + if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.IMMEDIATE_FLOW) { + currentMap = typedStatistics.currentImmediate(); + previousMap = typedStatistics.previousImmediate(); + + List fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap, + isAllInstType, instType, TypedFlowEntryWithLoad.shortPollInterval()); + if (fel.size() > 0) { + retTFEL.addAll(fel); + } + } + + if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.SHORT_FLOW) { + currentMap = typedStatistics.currentShort(); + previousMap = typedStatistics.previousShort(); + + List fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap, + isAllInstType, instType, TypedFlowEntryWithLoad.shortPollInterval()); + if (fel.size() > 0) { + retTFEL.addAll(fel); + } + } + + if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.MID_FLOW) { + currentMap = typedStatistics.currentMid(); + previousMap = typedStatistics.previousMid(); + + List fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap, + isAllInstType, instType, TypedFlowEntryWithLoad.midPollInterval()); + if (fel.size() > 0) { + retTFEL.addAll(fel); + } + } + + if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.LONG_FLOW) { + currentMap = typedStatistics.currentLong(); + previousMap = typedStatistics.previousLong(); + + List fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap, + isAllInstType, instType, TypedFlowEntryWithLoad.longPollInterval()); + if (fel.size() > 0) { + retTFEL.addAll(fel); + } + } + + if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.UNKNOWN_FLOW) { + currentMap = typedStatistics.currentUnknown(); + previousMap = typedStatistics.previousUnknown(); + + List fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap, + isAllInstType, instType, TypedFlowEntryWithLoad.avgPollInterval()); + if (fel.size() > 0) { + retTFEL.addAll(fel); + } + } + + return retTFEL; + } + + private List typedFlowEntryLoadByInstInternal(ConnectPoint cp, + Map currentMap, + Map previousMap, + boolean isAllInstType, + Instruction.Type instType, + int liveTypePollInterval) { + List fel = new ArrayList<>(); + + for (TypedStoredFlowEntry tfe : currentMap.values()) { + if (isAllInstType || + tfe.treatment().allInstructions().stream(). + filter(i -> i.type() == instType). + findAny().isPresent()) { + long currentBytes = tfe.bytes(); + long previousBytes = previousMap.getOrDefault(tfe, new DefaultTypedFlowEntry((FlowRule) tfe)).bytes(); + Load fLoad = new DefaultLoad(currentBytes, previousBytes, liveTypePollInterval); + fel.add(new TypedFlowEntryWithLoad(cp, tfe, fLoad)); + } + } + + return fel; + } + + private List loadTopnPortInternal(ConnectPoint cp, + TypedStoredFlowEntry.FlowLiveType liveType, + Instruction.Type instType, + int topn) { + List fel = loadAllPortInternal(cp, liveType, instType); + + // Sort with descending order of load + List tfel = + fel.stream().sorted(Comparators.TYPEFLOWENTRY_WITHLOAD_COMPARATOR). + limit(topn).collect(Collectors.toList()); + + return tfel; + } + + private long aggregateBytesSet(Set setFE) { + return setFE.stream().mapToLong(FlowEntry::bytes).sum(); + } + + private long aggregateBytesMap(Map mapFE) { + return mapFE.values().stream().mapToLong(FlowEntry::bytes).sum(); + } + + /** + * Internal data class holding two set of typed flow entries. + */ + private static class TypedStatistics { + private final ImmutableSet currentAll; + private final ImmutableSet previousAll; + + private final Map currentImmediate = new HashMap<>(); + private final Map previousImmediate = new HashMap<>(); + + private final Map currentShort = new HashMap<>(); + private final Map previousShort = new HashMap<>(); + + private final Map currentMid = new HashMap<>(); + private final Map previousMid = new HashMap<>(); + + private final Map currentLong = new HashMap<>(); + private final Map previousLong = new HashMap<>(); + + private final Map currentUnknown = new HashMap<>(); + private final Map previousUnknown = new HashMap<>(); + + public TypedStatistics(Set current, Set previous) { + this.currentAll = ImmutableSet.copyOf(checkNotNull(current)); + this.previousAll = ImmutableSet.copyOf(checkNotNull(previous)); + + currentAll.forEach(fe -> { + TypedStoredFlowEntry tfe = TypedFlowEntryWithLoad.newTypedStoredFlowEntry(fe); + + switch (tfe.flowLiveType()) { + case IMMEDIATE_FLOW: + currentImmediate.put(fe, tfe); + break; + case SHORT_FLOW: + currentShort.put(fe, tfe); + break; + case MID_FLOW: + currentMid.put(fe, tfe); + break; + case LONG_FLOW: + currentLong.put(fe, tfe); + break; + default: + currentUnknown.put(fe, tfe); + break; + } + }); + + previousAll.forEach(fe -> { + TypedStoredFlowEntry tfe = TypedFlowEntryWithLoad.newTypedStoredFlowEntry(fe); + + switch (tfe.flowLiveType()) { + case IMMEDIATE_FLOW: + if (currentImmediate.containsKey(fe)) { + previousImmediate.put(fe, tfe); + } else if (currentShort.containsKey(fe)) { + previousShort.put(fe, tfe); + } else if (currentMid.containsKey(fe)) { + previousMid.put(fe, tfe); + } else if (currentLong.containsKey(fe)) { + previousLong.put(fe, tfe); + } else { + previousUnknown.put(fe, tfe); + } + break; + case SHORT_FLOW: + if (currentShort.containsKey(fe)) { + previousShort.put(fe, tfe); + } else if (currentMid.containsKey(fe)) { + previousMid.put(fe, tfe); + } else if (currentLong.containsKey(fe)) { + previousLong.put(fe, tfe); + } else { + previousUnknown.put(fe, tfe); + } + break; + case MID_FLOW: + if (currentMid.containsKey(fe)) { + previousMid.put(fe, tfe); + } else if (currentLong.containsKey(fe)) { + previousLong.put(fe, tfe); + } else { + previousUnknown.put(fe, tfe); + } + break; + case LONG_FLOW: + if (currentLong.containsKey(fe)) { + previousLong.put(fe, tfe); + } else { + previousUnknown.put(fe, tfe); + } + break; + default: + previousUnknown.put(fe, tfe); + break; + } + }); + } + + /** + * Returns flow entries as the current value. + * + * @return flow entries as the current value + */ + public ImmutableSet current() { + return currentAll; + } + + /** + * Returns flow entries as the previous value. + * + * @return flow entries as the previous value + */ + public ImmutableSet previous() { + return previousAll; + } + + public Map currentImmediate() { + return currentImmediate; + } + public Map previousImmediate() { + return previousImmediate; + } + public Map currentShort() { + return currentShort; + } + public Map previousShort() { + return previousShort; + } + public Map currentMid() { + return currentMid; + } + public Map previousMid() { + return previousMid; + } + public Map currentLong() { + return currentLong; + } + public Map previousLong() { + return previousLong; + } + public Map currentUnknown() { + return currentUnknown; + } + public Map previousUnknown() { + return previousUnknown; + } + + /** + * Validates values are not empty. + * + * @return false if either of the sets is empty. Otherwise, true. + */ + public boolean isValid() { + return !(currentAll.isEmpty() || previousAll.isEmpty()); + } + + @Override + public int hashCode() { + return Objects.hash(currentAll, previousAll); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof TypedStatistics)) { + return false; + } + final TypedStatistics other = (TypedStatistics) obj; + return Objects.equals(this.currentAll, other.currentAll) && + Objects.equals(this.previousAll, other.previousAll); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("current", currentAll) + .add("previous", previousAll) + .toString(); + } + } + + private void checkLoadValidity(Set current, Set previous) { + current.stream().forEach(c -> { + FlowEntry f = previous.stream().filter(p -> c.equals(p)). + findAny().orElse(null); + if (f != null && c.bytes() < f.bytes()) { + log.debug("FlowStatisticManager:checkLoadValidity():" + + "Error: " + c + " :Previous bytes=" + f.bytes() + + " is larger than current bytes=" + c.bytes() + " !!!"); + } + }); + + } + + /** + * Creates a predicate that checks the instruction type of a flow entry is the same as + * the specified instruction type. + * + * @param instType instruction type to be checked + * @return predicate + */ + private static Predicate hasInstructionType(Instruction.Type instType) { + return new Predicate() { + @Override + public boolean apply(FlowEntry flowEntry) { + List allInstructions = flowEntry.treatment().allInstructions(); + + return allInstructions.stream().filter(i -> i.type() == instType).findAny().isPresent(); + } + }; + } + + /** + * Internal flow rule event listener for FlowStatisticManager. + */ + private class InternalFlowRuleStatsListener implements FlowRuleListener { + + @Override + public void event(FlowRuleEvent event) { + FlowRule rule = event.subject(); + switch (event.type()) { + case RULE_ADDED: + if (rule instanceof FlowEntry) { + flowStatisticStore.addFlowStatistic((FlowEntry) rule); + } + break; + case RULE_UPDATED: + flowStatisticStore.updateFlowStatistic((FlowEntry) rule); + break; + case RULE_ADD_REQUESTED: + break; + case RULE_REMOVE_REQUESTED: + break; + case RULE_REMOVED: + flowStatisticStore.removeFlowStatistic(rule); + break; + default: + log.warn("Unknown flow rule event {}", event); + } + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java index a238c7fb..8347ee38 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java @@ -27,6 +27,8 @@ import org.apache.felix.scr.annotations.Service; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DefaultEdgeLink; import org.onosproject.net.DefaultPath; +import org.onosproject.net.DisjointPath; +import org.onosproject.net.DefaultDisjointPath; import org.onosproject.net.DeviceId; import org.onosproject.net.EdgeLink; import org.onosproject.net.ElementId; @@ -46,6 +48,8 @@ import org.slf4j.Logger; import java.util.List; import java.util.Set; +import java.util.Map; + import static com.google.common.base.Preconditions.checkNotNull; import static org.slf4j.LoggerFactory.getLogger; @@ -128,6 +132,84 @@ public class PathManager implements PathService { return edgeToEdgePaths(srcEdge, dstEdge, paths); } + @Override + public Set getDisjointPaths(ElementId src, ElementId dst) { + return getDisjointPaths(src, dst, (LinkWeight) null); + } + + @Override + public Set getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight) { + checkNotNull(src, ELEMENT_ID_NULL); + checkNotNull(dst, ELEMENT_ID_NULL); + + // Get the source and destination edge locations + EdgeLink srcEdge = getEdgeLink(src, true); + EdgeLink dstEdge = getEdgeLink(dst, false); + + // If either edge is null, bail with no paths. + if (srcEdge == null || dstEdge == null) { + return ImmutableSet.of(); + } + + DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src; + DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst; + + // If the source and destination are on the same edge device, there + // is just one path, so build it and return it. + if (srcDevice.equals(dstDevice)) { + return edgeToEdgePathsDisjoint(srcEdge, dstEdge); + } + + // Otherwise get all paths between the source and destination edge + // devices. + Topology topology = topologyService.currentTopology(); + Set paths = weight == null ? + topologyService.getDisjointPaths(topology, srcDevice, dstDevice) : + topologyService.getDisjointPaths(topology, srcDevice, dstDevice, weight); + + return edgeToEdgePathsDisjoint(srcEdge, dstEdge, paths); + } + + @Override + public Set getDisjointPaths(ElementId src, ElementId dst, + Map riskProfile) { + return getDisjointPaths(src, dst, null, riskProfile); + } + + @Override + public Set getDisjointPaths(ElementId src, ElementId dst, LinkWeight weight, + Map riskProfile) { + checkNotNull(src, ELEMENT_ID_NULL); + checkNotNull(dst, ELEMENT_ID_NULL); + + // Get the source and destination edge locations + EdgeLink srcEdge = getEdgeLink(src, true); + EdgeLink dstEdge = getEdgeLink(dst, false); + + // If either edge is null, bail with no paths. + if (srcEdge == null || dstEdge == null) { + return ImmutableSet.of(); + } + + DeviceId srcDevice = srcEdge != NOT_HOST ? srcEdge.dst().deviceId() : (DeviceId) src; + DeviceId dstDevice = dstEdge != NOT_HOST ? dstEdge.src().deviceId() : (DeviceId) dst; + + // If the source and destination are on the same edge device, there + // is just one path, so build it and return it. + if (srcDevice.equals(dstDevice)) { + return edgeToEdgePathsDisjoint(srcEdge, dstEdge); + } + + // Otherwise get all paths between the source and destination edge + // devices. + Topology topology = topologyService.currentTopology(); + Set paths = weight == null ? + topologyService.getDisjointPaths(topology, srcDevice, dstDevice, riskProfile) : + topologyService.getDisjointPaths(topology, srcDevice, dstDevice, weight, riskProfile); + + return edgeToEdgePathsDisjoint(srcEdge, dstEdge, paths); + } + // Finds the host edge link if the element ID is a host id of an existing // host. Otherwise, if the host does not exist, it returns null and if // the element ID is not a host ID, returns NOT_HOST edge link. @@ -162,6 +244,20 @@ public class PathManager implements PathService { return endToEndPaths; } + private Set edgeToEdgePathsDisjoint(EdgeLink srcLink, EdgeLink dstLink) { + Set endToEndPaths = Sets.newHashSetWithExpectedSize(1); + endToEndPaths.add(edgeToEdgePathD(srcLink, dstLink, null)); + return endToEndPaths; + } + + private Set edgeToEdgePathsDisjoint(EdgeLink srcLink, EdgeLink dstLink, Set paths) { + Set endToEndPaths = Sets.newHashSetWithExpectedSize(paths.size()); + for (DisjointPath path : paths) { + endToEndPaths.add(edgeToEdgePathD(srcLink, dstLink, path)); + } + return endToEndPaths; + } + // Produces a direct edge-to-edge path. private Path edgeToEdgePath(EdgeLink srcLink, EdgeLink dstLink, Path path) { List links = Lists.newArrayListWithCapacity(2); @@ -179,6 +275,13 @@ public class PathManager implements PathService { return new DefaultPath(PID, links, 2); } + // Produces a direct edge-to-edge path. + private DisjointPath edgeToEdgePathD(EdgeLink srcLink, EdgeLink dstLink, DisjointPath path) { + return new DefaultDisjointPath(PID, (DefaultPath) edgeToEdgePath(srcLink, dstLink, path.primary()), + (DefaultPath) edgeToEdgePath(srcLink, dstLink, path.backup())); + } + + // Special value for edge link to represent that this is really not an // edge link since the src or dst are really an infrastructure device. private static class NotHost extends DefaultEdgeLink implements EdgeLink { diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java index 04c4f1c1..4425e1c1 100644 --- a/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java @@ -21,6 +21,7 @@ import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; +import org.onosproject.net.DisjointPath; import org.onosproject.net.provider.AbstractListenerProviderRegistry; import org.onosproject.event.Event; import org.onosproject.net.ConnectPoint; @@ -46,6 +47,7 @@ import org.slf4j.Logger; import java.util.List; import java.util.Set; +import java.util.Map; import static com.google.common.base.Preconditions.checkNotNull; import static org.onosproject.security.AppGuard.checkPermission; @@ -60,7 +62,7 @@ import static org.onosproject.security.AppPermission.Type.*; @Service public class TopologyManager extends AbstractListenerProviderRegistry + TopologyProvider, TopologyProviderService> implements TopologyService, TopologyProviderRegistry { public static final String TOPOLOGY_NULL = "Topology cannot be null"; @@ -68,6 +70,7 @@ public class TopologyManager private static final String CLUSTER_ID_NULL = "Cluster ID cannot be null"; private static final String CLUSTER_NULL = "Topology cluster cannot be null"; public static final String CONNECTION_POINT_NULL = "Connection point cannot be null"; + public static final String LINK_WEIGHT_NULL = "Link weight cannot be null"; private final Logger log = getLogger(getClass()); @@ -161,6 +164,44 @@ public class TopologyManager return store.getPaths(topology, src, dst, weight); } + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst) { + checkNotNull(topology, TOPOLOGY_NULL); + checkNotNull(src, DEVICE_ID_NULL); + checkNotNull(dst, DEVICE_ID_NULL); + return store.getDisjointPaths(topology, src, dst); + } + + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, + DeviceId dst, LinkWeight weight) { + checkNotNull(topology, TOPOLOGY_NULL); + checkNotNull(src, DEVICE_ID_NULL); + checkNotNull(dst, DEVICE_ID_NULL); + checkNotNull(weight, LINK_WEIGHT_NULL); + return store.getDisjointPaths(topology, src, dst, weight); + } + + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + Map riskProfile) { + checkNotNull(topology, TOPOLOGY_NULL); + checkNotNull(src, DEVICE_ID_NULL); + checkNotNull(dst, DEVICE_ID_NULL); + return store.getDisjointPaths(topology, src, dst, riskProfile); + } + + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, + DeviceId dst, LinkWeight weight, + Map riskProfile) { + checkNotNull(topology, TOPOLOGY_NULL); + checkNotNull(src, DEVICE_ID_NULL); + checkNotNull(dst, DEVICE_ID_NULL); + checkNotNull(weight, LINK_WEIGHT_NULL); + return store.getDisjointPaths(topology, src, dst, weight, riskProfile); + } + @Override public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) { checkPermission(TOPOLOGY_READ); diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ComponentConfigLoaderTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ComponentConfigLoaderTest.java new file mode 100644 index 00000000..0320cf77 --- /dev/null +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ComponentConfigLoaderTest.java @@ -0,0 +1,126 @@ +/* + * 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.cfg.impl; + +import com.google.common.collect.ImmutableSet; +import com.google.common.io.Files; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.cfg.ComponentConfigAdapter; +import org.slf4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.util.Set; + +import static com.google.common.io.ByteStreams.toByteArray; +import static com.google.common.io.Files.write; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * UnitTest for ComponentLoader. + */ +public class ComponentConfigLoaderTest { + + static final File TEST_DIR = Files.createTempDir(); + + private static final String FOO_COMPONENT = "fooComponent"; + + private ComponentConfigLoader loader; + + private TestConfigService service; + + private final Logger log = getLogger(getClass()); + + /* + * Method to SetUp the test environment with test file, a config loader a service, + * and assign it to the loader.configService for the test. + */ + @Before + public void setUp() { + ComponentConfigLoader.cfgFile = new File(TEST_DIR, "test.json"); + loader = new ComponentConfigLoader(); + service = new TestConfigService(); + loader.configService = service; + } + + /* + * Tests that the component in the json receives the correct configuration. + */ + @Test + public void basics() throws IOException { + stageTestResource("basic.json"); + loader.activate(); + assertEquals("incorrect component", FOO_COMPONENT, service.component); + } + + /* + * Tests that the component is null if the file has a bad configuration format + * for which it yielded an exception. Can't test the exception because it happens + * in a different thread. + */ + @Test + public void badConfig() throws IOException { + stageTestResource("badConfig.json"); + loader.activate(); + assertNull("incorrect configuration", service.component); + + } + + /* + * Writes the necessary file for the tests in the temporary directory + */ + static void stageTestResource(String name) throws IOException { + byte[] bytes = toByteArray(ComponentConfigLoaderTest.class.getResourceAsStream(name)); + write(bytes, ComponentConfigLoader.cfgFile); + } + + /* + * Mockup class for the config service. + */ + private class TestConfigService extends ComponentConfigAdapter { + + protected String component; + protected String name; + protected String value; + + @Override + public Set getComponentNames() { + return ImmutableSet.of(FOO_COMPONENT); + } + + @Override + public void preSetProperty(String componentName, String name, String value) { + log.info("preSet"); + this.component = componentName; + this.name = name; + this.value = value; + + } + + @Override + public void setProperty(String componentName, String name, String value) { + log.info("Set"); + this.component = componentName; + this.name = name; + this.value = value; + + } + } +} \ No newline at end of file diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java index d167197a..3cd2ca2b 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java @@ -23,10 +23,12 @@ import org.junit.Before; import org.junit.Test; import org.onlab.packet.ARP; import org.onlab.packet.Ethernet; +import org.onlab.packet.IPv6; import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; import org.onlab.packet.VlanId; +import org.onlab.packet.ndp.NeighborSolicitation; import org.onosproject.incubator.net.intf.Interface; import org.onosproject.incubator.net.intf.InterfaceService; import org.onosproject.net.ConnectPoint; @@ -64,14 +66,22 @@ import static org.junit.Assert.assertTrue; public class HostMonitorTest { - private static final IpAddress TARGET_IP_ADDR = + private static final IpAddress TARGET_IPV4_ADDR = IpAddress.valueOf("10.0.0.1"); - private static final IpAddress SOURCE_ADDR = + private static final IpAddress SOURCE_IPV4_ADDR = IpAddress.valueOf("10.0.0.99"); private static final InterfaceIpAddress IA1 = - new InterfaceIpAddress(SOURCE_ADDR, IpPrefix.valueOf("10.0.0.0/24")); + new InterfaceIpAddress(SOURCE_IPV4_ADDR, IpPrefix.valueOf("10.0.0.0/24")); private MacAddress sourceMac = MacAddress.valueOf(1L); + private static final IpAddress TARGET_IPV6_ADDR = + IpAddress.valueOf("1000::1"); + private static final IpAddress SOURCE_IPV6_ADDR = + IpAddress.valueOf("1000::f"); + private static final InterfaceIpAddress IA2 = + new InterfaceIpAddress(SOURCE_IPV6_ADDR, IpPrefix.valueOf("1000::/64")); + private MacAddress sourceMac2 = MacAddress.valueOf(2L); + private EdgePortService edgePortService; private HostMonitor hostMonitor; @@ -90,7 +100,36 @@ public class HostMonitorTest { } @Test - public void testMonitorHostExists() throws Exception { + public void testMonitorIpv4HostExists() throws Exception { + ProviderId id = new ProviderId("fake://", "id"); + + Host host = createMock(Host.class); + expect(host.providerId()).andReturn(id); + replay(host); + + HostManager hostManager = createMock(HostManager.class); + expect(hostManager.getHostsByIp(TARGET_IPV4_ADDR)) + .andReturn(Collections.singleton(host)); + replay(hostManager); + + HostProvider hostProvider = createMock(HostProvider.class); + expect(hostProvider.id()).andReturn(id).anyTimes(); + hostProvider.triggerProbe(host); + expectLastCall().once(); + replay(hostProvider); + + hostMonitor = new HostMonitor(null, hostManager, null, edgePortService); + + hostMonitor.registerHostProvider(hostProvider); + hostMonitor.addMonitoringFor(TARGET_IPV4_ADDR); + + hostMonitor.run(null); + + verify(hostProvider); + } + + @Test + public void testMonitorIpv6HostExists() throws Exception { ProviderId id = new ProviderId("fake://", "id"); Host host = createMock(Host.class); @@ -98,7 +137,7 @@ public class HostMonitorTest { replay(host); HostManager hostManager = createMock(HostManager.class); - expect(hostManager.getHostsByIp(TARGET_IP_ADDR)) + expect(hostManager.getHostsByIp(TARGET_IPV6_ADDR)) .andReturn(Collections.singleton(host)); replay(hostManager); @@ -111,7 +150,7 @@ public class HostMonitorTest { hostMonitor = new HostMonitor(null, hostManager, null, edgePortService); hostMonitor.registerHostProvider(hostProvider); - hostMonitor.addMonitoringFor(TARGET_IP_ADDR); + hostMonitor.addMonitoringFor(TARGET_IPV6_ADDR); hostMonitor.run(null); @@ -119,7 +158,7 @@ public class HostMonitorTest { } @Test - public void testMonitorHostDoesNotExist() throws Exception { + public void testMonitorIpv4HostDoesNotExist() throws Exception { HostManager hostManager = createMock(HostManager.class); @@ -140,12 +179,12 @@ public class HostMonitorTest { ConnectPoint cp = new ConnectPoint(devId, portNum); - expect(hostManager.getHostsByIp(TARGET_IP_ADDR)) + expect(hostManager.getHostsByIp(TARGET_IPV4_ADDR)) .andReturn(Collections.emptySet()).anyTimes(); replay(hostManager); InterfaceService interfaceService = createMock(InterfaceService.class); - expect(interfaceService.getMatchingInterface(TARGET_IP_ADDR)) + expect(interfaceService.getMatchingInterface(TARGET_IPV4_ADDR)) .andReturn(new Interface(cp, Collections.singleton(IA1), sourceMac, VlanId.NONE)) .anyTimes(); replay(interfaceService); @@ -156,7 +195,7 @@ public class HostMonitorTest { // Run the test hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService); - hostMonitor.addMonitoringFor(TARGET_IP_ADDR); + hostMonitor.addMonitoringFor(TARGET_IPV4_ADDR); hostMonitor.run(null); @@ -178,16 +217,85 @@ public class HostMonitorTest { Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length); assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID()); ARP arp = (ARP) eth.getPayload(); - assertArrayEquals(SOURCE_ADDR.toOctets(), + assertArrayEquals(SOURCE_IPV4_ADDR.toOctets(), arp.getSenderProtocolAddress()); assertArrayEquals(sourceMac.toBytes(), arp.getSenderHardwareAddress()); - assertArrayEquals(TARGET_IP_ADDR.toOctets(), + assertArrayEquals(TARGET_IPV4_ADDR.toOctets(), arp.getTargetProtocolAddress()); } @Test - public void testMonitorHostDoesNotExistWithVlan() throws Exception { + public void testMonitorIpv6HostDoesNotExist() throws Exception { + + HostManager hostManager = createMock(HostManager.class); + + DeviceId devId = DeviceId.deviceId("fake"); + + Device device = createMock(Device.class); + expect(device.id()).andReturn(devId).anyTimes(); + replay(device); + + PortNumber portNum = PortNumber.portNumber(2L); + + Port port = createMock(Port.class); + expect(port.number()).andReturn(portNum).anyTimes(); + replay(port); + + TestDeviceService deviceService = new TestDeviceService(); + deviceService.addDevice(device, Collections.singleton(port)); + + ConnectPoint cp = new ConnectPoint(devId, portNum); + + expect(hostManager.getHostsByIp(TARGET_IPV6_ADDR)) + .andReturn(Collections.emptySet()).anyTimes(); + replay(hostManager); + + InterfaceService interfaceService = createMock(InterfaceService.class); + expect(interfaceService.getMatchingInterface(TARGET_IPV6_ADDR)) + .andReturn(new Interface(cp, Collections.singleton(IA2), sourceMac2, VlanId.NONE)) + .anyTimes(); + replay(interfaceService); + + TestPacketService packetService = new TestPacketService(); + + + // Run the test + hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService); + + hostMonitor.addMonitoringFor(TARGET_IPV6_ADDR); + hostMonitor.run(null); + + + // Check that a packet was sent to our PacketService and that it has + // the properties we expect + assertEquals(1, packetService.packets.size()); + OutboundPacket packet = packetService.packets.get(0); + + // Check the output port is correct + assertEquals(1, packet.treatment().immediate().size()); + Instruction instruction = packet.treatment().immediate().get(0); + assertTrue(instruction instanceof OutputInstruction); + OutputInstruction oi = (OutputInstruction) instruction; + assertEquals(portNum, oi.port()); + + // Check the output packet is correct (well the important bits anyway) + final byte[] pktData = new byte[packet.data().remaining()]; + packet.data().get(pktData); + Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length); + assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID()); + IPv6 ipv6 = (IPv6) eth.getPayload(); + assertArrayEquals(SOURCE_IPV6_ADDR.toOctets(), ipv6.getSourceAddress()); + + NeighborSolicitation ns = + (NeighborSolicitation) ipv6.getPayload().getPayload(); + assertArrayEquals(sourceMac2.toBytes(), ns.getOptions().get(0).data()); + + assertArrayEquals(TARGET_IPV6_ADDR.toOctets(), ns.getTargetAddress()); + } + + @Test + public void testMonitorIpv4HostDoesNotExistWithVlan() throws Exception { HostManager hostManager = createMock(HostManager.class); @@ -209,12 +317,12 @@ public class HostMonitorTest { ConnectPoint cp = new ConnectPoint(devId, portNum); - expect(hostManager.getHostsByIp(TARGET_IP_ADDR)) + expect(hostManager.getHostsByIp(TARGET_IPV4_ADDR)) .andReturn(Collections.emptySet()).anyTimes(); replay(hostManager); InterfaceService interfaceService = createMock(InterfaceService.class); - expect(interfaceService.getMatchingInterface(TARGET_IP_ADDR)) + expect(interfaceService.getMatchingInterface(TARGET_IPV4_ADDR)) .andReturn(new Interface(cp, Collections.singleton(IA1), sourceMac, VlanId.vlanId(vlan))) .anyTimes(); replay(interfaceService); @@ -225,7 +333,7 @@ public class HostMonitorTest { // Run the test hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService); - hostMonitor.addMonitoringFor(TARGET_IP_ADDR); + hostMonitor.addMonitoringFor(TARGET_IPV4_ADDR); hostMonitor.run(null); @@ -247,14 +355,84 @@ public class HostMonitorTest { Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length); assertEquals(vlan, eth.getVlanID()); ARP arp = (ARP) eth.getPayload(); - assertArrayEquals(SOURCE_ADDR.toOctets(), + assertArrayEquals(SOURCE_IPV4_ADDR.toOctets(), arp.getSenderProtocolAddress()); assertArrayEquals(sourceMac.toBytes(), arp.getSenderHardwareAddress()); - assertArrayEquals(TARGET_IP_ADDR.toOctets(), + assertArrayEquals(TARGET_IPV4_ADDR.toOctets(), arp.getTargetProtocolAddress()); } + @Test + public void testMonitorIpv6HostDoesNotExistWithVlan() throws Exception { + + HostManager hostManager = createMock(HostManager.class); + + DeviceId devId = DeviceId.deviceId("fake"); + short vlan = 5; + + Device device = createMock(Device.class); + expect(device.id()).andReturn(devId).anyTimes(); + replay(device); + + PortNumber portNum = PortNumber.portNumber(1L); + + Port port = createMock(Port.class); + expect(port.number()).andReturn(portNum).anyTimes(); + replay(port); + + TestDeviceService deviceService = new TestDeviceService(); + deviceService.addDevice(device, Collections.singleton(port)); + + ConnectPoint cp = new ConnectPoint(devId, portNum); + + expect(hostManager.getHostsByIp(TARGET_IPV6_ADDR)) + .andReturn(Collections.emptySet()).anyTimes(); + replay(hostManager); + + InterfaceService interfaceService = createMock(InterfaceService.class); + expect(interfaceService.getMatchingInterface(TARGET_IPV6_ADDR)) + .andReturn(new Interface(cp, Collections.singleton(IA2), sourceMac2, VlanId.vlanId(vlan))) + .anyTimes(); + replay(interfaceService); + + TestPacketService packetService = new TestPacketService(); + + + // Run the test + hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService); + + hostMonitor.addMonitoringFor(TARGET_IPV6_ADDR); + hostMonitor.run(null); + + + // Check that a packet was sent to our PacketService and that it has + // the properties we expect + assertEquals(1, packetService.packets.size()); + OutboundPacket packet = packetService.packets.get(0); + + // Check the output port is correct + assertEquals(1, packet.treatment().immediate().size()); + Instruction instruction = packet.treatment().immediate().get(0); + assertTrue(instruction instanceof OutputInstruction); + OutputInstruction oi = (OutputInstruction) instruction; + assertEquals(portNum, oi.port()); + + // Check the output packet is correct (well the important bits anyway) + final byte[] pktData = new byte[packet.data().remaining()]; + packet.data().get(pktData); + Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length); + assertEquals(vlan, eth.getVlanID()); + IPv6 ipv6 = (IPv6) eth.getPayload(); + assertArrayEquals(SOURCE_IPV6_ADDR.toOctets(), ipv6.getSourceAddress()); + + NeighborSolicitation ns = + (NeighborSolicitation) ipv6.getPayload().getPayload(); + assertArrayEquals(sourceMac2.toBytes(), ns.getOptions().get(0).data()); + + assertArrayEquals(TARGET_IPV6_ADDR.toOctets(), ns.getTargetAddress()); + } + class TestPacketService extends PacketServiceAdapter { List packets = new ArrayList<>(); diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java index 4bf32f43..3f40de09 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java @@ -157,7 +157,7 @@ public class IntentManagerTest { private static class MockInstallableIntent extends FlowRuleIntent { public MockInstallableIntent() { - super(APPID, Collections.singletonList(new MockFlowRule(100))); + super(APPID, Collections.singletonList(new MockFlowRule(100)), Collections.emptyList()); } } diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java index eb7a3936..03d664d3 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java @@ -31,8 +31,7 @@ import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.IntentTestsMocks; import org.onosproject.net.intent.LinkCollectionIntent; import org.onosproject.net.intent.MultiPointToSinglePointIntent; -import org.onosproject.net.topology.LinkWeight; -import org.onosproject.net.topology.PathService; +import org.onosproject.net.topology.PathServiceAdapter; import java.util.HashSet; import java.util.List; @@ -60,7 +59,7 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes /** * Mock path service for creating paths within the test. */ - private static class MockPathService implements PathService { + private static class MockPathService extends PathServiceAdapter { final String[] pathHops; @@ -86,11 +85,6 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes return result; } - - @Override - public Set getPaths(ElementId src, ElementId dst, LinkWeight weight) { - return null; - } } /** diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java index 2f40b37a..38a116dd 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java @@ -27,18 +27,12 @@ import org.onosproject.net.DefaultLink; import org.onosproject.net.DefaultPath; import org.onosproject.net.Link; import org.onosproject.net.OchSignalType; -import org.onosproject.net.flow.DefaultTrafficSelector; -import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.FlowRule; -import org.onosproject.net.flow.TrafficSelector; -import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.intent.FlowRuleIntent; import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.IntentExtensionService; -import org.onosproject.net.intent.IntentTestsMocks; import org.onosproject.net.intent.MockIdGenerator; import org.onosproject.net.intent.OpticalPathIntent; -import org.onosproject.net.provider.ProviderId; import java.util.Arrays; import java.util.Collection; @@ -63,16 +57,11 @@ public class OpticalPathIntentCompilerTest { private final IdGenerator idGenerator = new MockIdGenerator(); private OpticalPathIntentCompiler sut; - private final TrafficSelector selector = DefaultTrafficSelector.builder().build(); - private final TrafficTreatment treatment = DefaultTrafficTreatment.builder().build(); private final ApplicationId appId = new TestApplicationId("test"); - private final ProviderId pid = new ProviderId("of", "test"); private final ConnectPoint d1p1 = connectPoint("s1", 0); private final ConnectPoint d2p0 = connectPoint("s2", 0); private final ConnectPoint d2p1 = connectPoint("s2", 1); private final ConnectPoint d3p1 = connectPoint("s3", 1); - private final ConnectPoint d3p0 = connectPoint("s3", 10); - private final ConnectPoint d1p0 = connectPoint("s1", 10); private final List links = Arrays.asList( new DefaultLink(PID, d1p1, d2p0, DIRECT), @@ -103,7 +92,6 @@ public class OpticalPathIntentCompilerTest { intentExtensionService.registerCompiler(OpticalPathIntent.class, sut); intentExtensionService.unregisterCompiler(OpticalPathIntent.class); sut.intentManager = intentExtensionService; - sut.resourceService = new IntentTestsMocks.MockResourceService(); replay(coreService, intentExtensionService); } diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java index 2a2d0b54..1911da56 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java @@ -23,13 +23,11 @@ import org.onosproject.net.ElementId; import org.onosproject.net.Host; import org.onosproject.net.HostId; import org.onosproject.net.Path; -import org.onosproject.net.host.HostService; import org.onosproject.net.host.HostServiceAdapter; import org.onosproject.net.provider.ProviderId; import org.onosproject.net.topology.LinkWeight; import org.onosproject.net.topology.PathService; import org.onosproject.net.topology.Topology; -import org.onosproject.net.topology.TopologyService; import org.onosproject.net.topology.TopologyServiceAdapter; import java.util.HashMap; @@ -137,7 +135,7 @@ public class PathManagerTest { } // Fake entity to give out paths. - private class FakeTopoMgr extends TopologyServiceAdapter implements TopologyService { + private class FakeTopoMgr extends TopologyServiceAdapter { Set paths = new HashSet<>(); @Override @@ -152,7 +150,7 @@ public class PathManagerTest { } // Fake entity to give out hosts. - private class FakeHostMgr extends HostServiceAdapter implements HostService { + private class FakeHostMgr extends HostServiceAdapter { private Map hosts = new HashMap<>(); @Override diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java index f3cd28df..56133a0f 100644 --- a/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java @@ -114,7 +114,7 @@ public class TopologyManagerTest { link("c", 2, "d", 1), link("d", 1, "c", 2), link("d", 2, "a", 2), link("a", 2, "d", 2), link("e", 1, "f", 1), link("f", 1, "e", 1)); - GraphDescription data = new DefaultGraphDescription(4321L, devices, links); + GraphDescription data = new DefaultGraphDescription(4321L, System.currentTimeMillis(), devices, links); providerService.topologyChanged(data, null); } diff --git a/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badComponent.json b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badComponent.json new file mode 100644 index 00000000..5c0ac35d --- /dev/null +++ b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badComponent.json @@ -0,0 +1,5 @@ +{ + "org.onosproject.proxyarp.ProxyArp2": { + "testProperty": true + } +} \ No newline at end of file diff --git a/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badConfig.json b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badConfig.json new file mode 100644 index 00000000..a76552e5 --- /dev/null +++ b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/badConfig.json @@ -0,0 +1,5 @@ +{ + "fooComponent": { + badconfig + } +} \ No newline at end of file diff --git a/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/basic.json b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/basic.json new file mode 100644 index 00000000..dd329243 --- /dev/null +++ b/framework/src/onos/core/net/src/test/resources/org/onosproject/cfg/impl/basic.json @@ -0,0 +1,5 @@ +{ + "fooComponent": { + "testProperty": true + } +} \ No newline at end of file diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java index ff3e36ac..52a999a4 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java @@ -38,7 +38,7 @@ public interface Database extends DatabaseProxy, Resource * * Additionally, the database will be constructed with an database configuration that searches the classpath for - * three configuration files - {@code {name}}, {@code database}, {@code database-defaults}, {@code resource}, and + * three configuration files - {@code name}, {@code database}, {@code database-defaults}, {@code resource}, and * {@code resource-defaults} - in that order. The first resource is a configuration resource with the same name * as the map resource. If the resource is namespaced - e.g. `databases.my-database.conf` - then resource * configurations will be loaded according to namespaces as well; for example, `databases.conf`. @@ -54,7 +54,7 @@ public interface Database extends DatabaseProxy, Resource * * The database will be constructed with an database configuration that searches the classpath for - * three configuration files - {@code {name}}, {@code database}, {@code database-defaults}, {@code resource}, and + * three configuration files - {@code name}, {@code database}, {@code database-defaults}, {@code resource}, and * {@code resource-defaults} - in that order. The first resource is a configuration resource with the same name * as the database resource. If the resource is namespaced - e.g. `databases.my-database.conf` - then resource * configurations will be loaded according to namespaces as well; for example, `databases.conf`. diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java index fbc2c88d..6ea7c220 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java @@ -443,7 +443,10 @@ public class DatabaseManager implements StorageService, StorageAdminService { public void event(ApplicationEvent event) { if (event.type() == APP_UNINSTALLED || event.type() == APP_DEACTIVATED) { ApplicationId appId = event.subject().id(); - List mapsToRemove = ImmutableList.copyOf(mapsByApplication.get(appId)); + List mapsToRemove; + synchronized (mapsByApplication) { + mapsToRemove = ImmutableList.copyOf(mapsByApplication.get(appId)); + } mapsToRemove.forEach(DatabaseManager.this::unregisterMap); if (event.type() == APP_UNINSTALLED) { mapsToRemove.stream().filter(map -> map.purgeOnUninstall()).forEach(map -> map.clear()); diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java index 95f9e39a..1d81f998 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java @@ -16,14 +16,14 @@ package org.onosproject.store.consistent.impl; +import org.onosproject.store.service.Transaction; +import org.onosproject.store.service.Versioned; + import java.util.Collection; import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; -import org.onosproject.store.service.Transaction; -import org.onosproject.store.service.Versioned; - /** * Database proxy. */ @@ -45,6 +45,7 @@ public interface DatabaseProxy { /** * Returns the number of entries in map. + * * @param mapName map name * @return A completable future to be completed with the result once complete. */ @@ -62,7 +63,7 @@ public interface DatabaseProxy { * Checks whether the map contains a key. * * @param mapName map name - * @param key key to check. + * @param key key to check. * @return A completable future to be completed with the result once complete. */ CompletableFuture mapContainsKey(String mapName, K key); @@ -71,7 +72,7 @@ public interface DatabaseProxy { * Checks whether the map contains a value. * * @param mapName map name - * @param value The value to check. + * @param value The value to check. * @return A completable future to be completed with the result once complete. */ CompletableFuture mapContainsValue(String mapName, V value); @@ -80,7 +81,7 @@ public interface DatabaseProxy { * Gets a value from the map. * * @param mapName map name - * @param key The key to get. + * @param key The key to get. * @return A completable future to be completed with the result once complete. */ CompletableFuture> mapGet(String mapName, K key); @@ -88,11 +89,11 @@ public interface DatabaseProxy { /** * Updates the map. * - * @param mapName map name - * @param key The key to set - * @param valueMatch match for checking existing value - * @param versionMatch match for checking existing version - * @param value new value + * @param mapName map name + * @param key The key to set + * @param valueMatch match for checking existing value + * @param versionMatch match for checking existing version + * @param value new value * @return A completable future to be completed with the result once complete */ CompletableFuture>> mapUpdate( @@ -130,11 +131,11 @@ public interface DatabaseProxy { */ CompletableFuture>>> mapEntrySet(String mapName); - /** + /** * Atomically add the given value to current value of the specified counter. * * @param counterName counter name - * @param delta value to add + * @param delta value to add * @return updated value */ CompletableFuture counterAddAndGet(String counterName, long delta); @@ -143,11 +144,31 @@ public interface DatabaseProxy { * Atomically add the given value to current value of the specified counter. * * @param counterName counter name - * @param delta value to add + * @param delta value to add * @return previous value */ CompletableFuture counterGetAndAdd(String counterName, long delta); + + /** + * Atomically sets the given value to current value of the specified counter. + * + * @param counterName counter name + * @param value value to set + * @return void future + */ + CompletableFuture counterSet(String counterName, long value); + + /** + * Atomically sets the given counter to the specified update value if and only if the current value is equal to the + * expected value. + * @param counterName counter name + * @param expectedValue value to use for equivalence check + * @param update value to set if expected value is current value + * @return true if an update occurred, false otherwise + */ + CompletableFuture counterCompareAndSet(String counterName, long expectedValue, long update); + /** * Returns the current value of the specified atomic counter. * @@ -158,6 +179,7 @@ public interface DatabaseProxy { /** * Returns the size of queue. + * * @param queueName queue name * @return queue size */ @@ -165,14 +187,16 @@ public interface DatabaseProxy { /** * Inserts an entry into the queue. + * * @param queueName queue name - * @param entry queue entry + * @param entry queue entry * @return void future */ CompletableFuture queuePush(String queueName, byte[] entry); /** * Removes an entry from the queue if the queue is non-empty. + * * @param queueName queue name * @return entry future. Can be completed with null if queue is empty */ @@ -180,6 +204,7 @@ public interface DatabaseProxy { /** * Returns but does not remove an entry from the queue. + * * @param queueName queue name * @return entry. Can be null if queue is empty */ diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java index b3dd1c44..1136428b 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java @@ -16,18 +16,17 @@ package org.onosproject.store.consistent.impl; -import java.util.Collection; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.onosproject.store.service.Transaction; -import org.onosproject.store.service.Versioned; - import net.kuujo.copycat.state.Command; import net.kuujo.copycat.state.Initializer; import net.kuujo.copycat.state.Query; import net.kuujo.copycat.state.StateContext; +import org.onosproject.store.service.Transaction; +import org.onosproject.store.service.Versioned; + +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; /** * Database state. @@ -82,6 +81,9 @@ public interface DatabaseState { @Command Long counterAddAndGet(String counterName, long delta); + @Command + Boolean counterCompareAndSet(String counterName, long expectedValue, long updateValue); + @Command Long counterGetAndAdd(String counterName, long delta); diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncAtomicCounter.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncAtomicCounter.java index 7a439c34..d851eaa0 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncAtomicCounter.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncAtomicCounter.java @@ -18,6 +18,7 @@ package org.onosproject.store.consistent.impl; import org.onosproject.store.service.AsyncAtomicCounter; import java.util.concurrent.CompletableFuture; + import static com.google.common.base.Preconditions.checkNotNull; /** @@ -38,6 +39,8 @@ public class DefaultAsyncAtomicCounter implements AsyncAtomicCounter { private static final String GET_AND_ADD = "getAndAdd"; private static final String ADD_AND_GET = "addAndGet"; private static final String GET = "get"; + private static final String SET = "set"; + private static final String COMPARE_AND_SET = "compareAndSet"; public DefaultAsyncAtomicCounter(String name, Database database, @@ -72,13 +75,27 @@ public class DefaultAsyncAtomicCounter implements AsyncAtomicCounter { public CompletableFuture getAndAdd(long delta) { final MeteringAgent.Context timer = monitor.startTimer(GET_AND_ADD); return database.counterGetAndAdd(name, delta) - .whenComplete((r, e) -> timer.stop(e)); + .whenComplete((r, e) -> timer.stop(e)); } @Override public CompletableFuture addAndGet(long delta) { final MeteringAgent.Context timer = monitor.startTimer(ADD_AND_GET); return database.counterAddAndGet(name, delta) - .whenComplete((r, e) -> timer.stop(e)); + .whenComplete((r, e) -> timer.stop(e)); + } + + @Override + public CompletableFuture set(long value) { + final MeteringAgent.Context timer = monitor.startTimer(SET); + return database.counterSet(name, value) + .whenComplete((r, e) -> timer.stop(e)); + } + + @Override + public CompletableFuture compareAndSet(long expectedValue, long updateValue) { + final MeteringAgent.Context timer = monitor.startTimer(COMPARE_AND_SET); + return database.counterCompareAndSet(name, expectedValue, updateValue) + .whenComplete((r, e) -> timer.stop(e)); } } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicCounter.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicCounter.java index 64886e41..2d6a956c 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicCounter.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicCounter.java @@ -62,6 +62,16 @@ public class DefaultAtomicCounter implements AtomicCounter { return complete(asyncCounter.getAndAdd(delta)); } + @Override + public void set(long value) { + complete(asyncCounter.set(value)); + } + + @Override + public boolean compareAndSet(long expectedValue, long updateValue) { + return complete(asyncCounter.compareAndSet(expectedValue, updateValue)); + } + @Override public long get() { return complete(asyncCounter.get()); diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java index 4d9776ee..2a50fbd6 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java @@ -16,12 +16,15 @@ package org.onosproject.store.consistent.impl; -import net.kuujo.copycat.state.StateMachine; +import com.google.common.collect.Sets; import net.kuujo.copycat.resource.internal.AbstractResource; import net.kuujo.copycat.resource.internal.ResourceManager; +import net.kuujo.copycat.state.StateMachine; import net.kuujo.copycat.state.internal.DefaultStateMachine; import net.kuujo.copycat.util.concurrent.Futures; import net.kuujo.copycat.util.function.TriConsumer; +import org.onosproject.store.service.Transaction; +import org.onosproject.store.service.Versioned; import java.util.Collection; import java.util.Map; @@ -30,11 +33,6 @@ import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import java.util.function.Supplier; -import org.onosproject.store.service.Transaction; -import org.onosproject.store.service.Versioned; - -import com.google.common.collect.Sets; - /** * Default database. */ @@ -44,7 +42,7 @@ public class DefaultDatabase extends AbstractResource implements Datab private final Set> consumers = Sets.newCopyOnWriteArraySet(); private final TriConsumer watcher = new InternalStateMachineWatcher(); - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({"unchecked", "rawtypes"}) public DefaultDatabase(ResourceManager context) { super(context); this.stateMachine = new DefaultStateMachine(context, @@ -66,7 +64,7 @@ public class DefaultDatabase extends AbstractResource implements Datab * return the completed future result. * * @param supplier The supplier to call if the database is open. - * @param The future result type. + * @param The future result type. * @return A completable future that if this database is closed is immediately failed. */ protected CompletableFuture checkOpen(Supplier> supplier) { @@ -152,6 +150,16 @@ public class DefaultDatabase extends AbstractResource implements Datab return checkOpen(() -> proxy.counterGetAndAdd(counterName, delta)); } + @Override + public CompletableFuture counterSet(String counterName, long value) { + return checkOpen(() -> proxy.counterSet(counterName, value)); + } + + @Override + public CompletableFuture counterCompareAndSet(String counterName, long expectedValue, long update) { + return checkOpen(() -> proxy.counterCompareAndSet(counterName, expectedValue, update)); + } + @Override public CompletableFuture queueSize(String queueName) { return checkOpen(() -> proxy.queueSize(queueName)); diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java index 9a55ffb1..8943fc87 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java @@ -16,27 +16,26 @@ package org.onosproject.store.consistent.impl; +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import net.kuujo.copycat.state.Initializer; +import net.kuujo.copycat.state.StateContext; +import org.onosproject.store.service.DatabaseUpdate; +import org.onosproject.store.service.Transaction; +import org.onosproject.store.service.Versioned; + import java.util.Arrays; import java.util.Collection; import java.util.LinkedList; import java.util.Map; import java.util.Map.Entry; import java.util.Queue; +import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; -import java.util.Set; - -import org.onosproject.store.service.DatabaseUpdate; -import org.onosproject.store.service.Transaction; -import org.onosproject.store.service.Versioned; -import com.google.common.base.Objects; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import net.kuujo.copycat.state.Initializer; -import net.kuujo.copycat.state.StateContext; /** * Default database state. @@ -194,6 +193,11 @@ public class DefaultDatabaseState implements DatabaseState { return getCounter(counterName).getAndAdd(delta); } + @Override + public Boolean counterCompareAndSet(String counterName, long expectedValue, long updateValue) { + return getCounter(counterName).compareAndSet(expectedValue, updateValue); + } + @Override public Long counterGet(String counterName) { return getCounter(counterName).get(); diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/MutexExecutionManager.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/MutexExecutionManager.java new file mode 100644 index 00000000..d8593e37 --- /dev/null +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/MutexExecutionManager.java @@ -0,0 +1,315 @@ +/* + * 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.store.consistent.impl; + +import static org.slf4j.LoggerFactory.getLogger; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; +import org.onlab.util.Tools; +import org.onosproject.cluster.ClusterEvent; +import org.onosproject.cluster.ClusterEventListener; +import org.onosproject.cluster.ClusterService; +import org.onosproject.cluster.ControllerNode.State; +import org.onosproject.cluster.NodeId; +import org.onosproject.store.serializers.KryoNamespaces; +import org.onosproject.store.service.ConsistentMap; +import org.onosproject.store.service.ConsistentMapException; +import org.onosproject.store.service.MapEvent; +import org.onosproject.store.service.MapEventListener; +import org.onosproject.store.service.MutexExecutionService; +import org.onosproject.store.service.MutexTask; +import org.onosproject.store.service.Serializer; +import org.onosproject.store.service.StorageService; +import org.onosproject.store.service.Versioned; +import org.slf4j.Logger; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +/** + * Implementation of a MutexExecutionService. + */ +@Component(immediate = true) +@Service +public class MutexExecutionManager implements MutexExecutionService { + + private final Logger log = getLogger(getClass()); + + protected ConsistentMap lockMap; + protected NodeId localNodeId; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterService clusterService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected StorageService storageService; + + private final MapEventListener mapEventListener = new InternalLockMapEventListener(); + private final ClusterEventListener clusterEventListener = new InternalClusterEventListener(); + + private Map> pending = Maps.newConcurrentMap(); + private Map activeTasks = Maps.newConcurrentMap(); + + @Activate + public void activate() { + localNodeId = clusterService.getLocalNode().id(); + lockMap = storageService.consistentMapBuilder() + .withName("onos-mutexes") + .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API), MutexState.class)) + .withPartitionsDisabled() + .build(); + lockMap.addListener(mapEventListener); + clusterService.addListener(clusterEventListener); + releaseOldLocks(); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + lockMap.removeListener(mapEventListener); + pending.values().forEach(future -> future.cancel(true)); + activeTasks.forEach((k, v) -> { + v.stop(); + unlock(k); + }); + clusterService.removeListener(clusterEventListener); + log.info("Stopped"); + } + + @Override + public CompletableFuture execute(MutexTask task, String exclusionPath, Executor executor) { + return lock(exclusionPath) + .thenApply(state -> activeTasks.computeIfAbsent(exclusionPath, + k -> new InnerMutexTask(exclusionPath, + task, + state.term()))) + .thenAcceptAsync(t -> t.start(), executor) + .whenComplete((r, e) -> unlock(exclusionPath)); + } + + protected CompletableFuture lock(String exclusionPath) { + CompletableFuture future = + pending.computeIfAbsent(exclusionPath, k -> new CompletableFuture<>()); + tryLock(exclusionPath); + return future; + } + + /** + * Attempts to acquire lock for a path. If lock is held by some other node, adds this node to + * the wait list. + * @param exclusionPath exclusion path + */ + protected void tryLock(String exclusionPath) { + Tools.retryable(() -> lockMap.asJavaMap() + .compute(exclusionPath, + (k, v) -> MutexState.admit(v, localNodeId)), + ConsistentMapException.ConcurrentModification.class, + Integer.MAX_VALUE, + 100).get(); + } + + /** + * Releases lock for the specific path. This operation is idempotent. + * @param exclusionPath exclusion path + */ + protected void unlock(String exclusionPath) { + Tools.retryable(() -> lockMap.asJavaMap() + .compute(exclusionPath, (k, v) -> MutexState.evict(v, localNodeId)), + ConsistentMapException.ConcurrentModification.class, + Integer.MAX_VALUE, + 100).get(); + } + + /** + * Detects and releases all locks held by this node. + */ + private void releaseOldLocks() { + Maps.filterValues(lockMap.asJavaMap(), state -> localNodeId.equals(state.holder())) + .keySet() + .forEach(path -> { + log.info("Detected zombie task still holding lock for {}. Releasing lock.", path); + unlock(path); + }); + } + + private class InternalLockMapEventListener implements MapEventListener { + + @Override + public void event(MapEvent event) { + log.debug("Received {}", event); + if (event.type() == MapEvent.Type.UPDATE || event.type() == MapEvent.Type.INSERT) { + pending.computeIfPresent(event.key(), (k, future) -> { + MutexState state = Versioned.valueOrElse(event.value(), null); + if (state != null && localNodeId.equals(state.holder())) { + log.debug("Local node is now owner for {}", event.key()); + future.complete(state); + return null; + } else { + return future; + } + }); + InnerMutexTask task = activeTasks.get(event.key()); + if (task != null && task.term() < Versioned.valueOrElse(event.value(), null).term()) { + task.stop(); + } + } + } + } + + private class InternalClusterEventListener implements ClusterEventListener { + + @Override + public void event(ClusterEvent event) { + if (event.type() == ClusterEvent.Type.INSTANCE_DEACTIVATED || + event.type() == ClusterEvent.Type.INSTANCE_REMOVED) { + NodeId nodeId = event.subject().id(); + log.debug("{} is no longer active. Attemping to clean up its locks.", nodeId); + lockMap.asJavaMap().forEach((k, v) -> { + if (v.contains(nodeId)) { + lockMap.compute(k, (path, state) -> MutexState.evict(v, nodeId)); + } + }); + } + long activeNodes = clusterService.getNodes() + .stream() + .map(node -> clusterService.getState(node.id())) + .filter(State.ACTIVE::equals) + .count(); + if (clusterService.getNodes().size() > 1 && activeNodes == 1) { + log.info("This node is partitioned away from the cluster. Stopping all inflight executions"); + activeTasks.forEach((k, v) -> { + v.stop(); + }); + } + } + } + + private static final class MutexState { + + private final NodeId holder; + private final List waitList; + private final long term; + + public static MutexState admit(MutexState state, NodeId nodeId) { + if (state == null) { + return new MutexState(nodeId, 1L, Lists.newArrayList()); + } else if (state.holder() == null) { + return new MutexState(nodeId, state.term() + 1, Lists.newArrayList()); + } else { + if (!state.contains(nodeId)) { + NodeId newHolder = state.holder(); + List newWaitList = Lists.newArrayList(state.waitList()); + newWaitList.add(nodeId); + return new MutexState(newHolder, state.term(), newWaitList); + } else { + return state; + } + } + } + + public static MutexState evict(MutexState state, NodeId nodeId) { + return state.evict(nodeId); + } + + public MutexState evict(NodeId nodeId) { + if (nodeId.equals(holder)) { + if (waitList.isEmpty()) { + return new MutexState(null, term, waitList); + } + List newWaitList = Lists.newArrayList(waitList); + NodeId newHolder = newWaitList.remove(0); + return new MutexState(newHolder, term + 1, newWaitList); + } else { + NodeId newHolder = holder; + List newWaitList = Lists.newArrayList(waitList); + newWaitList.remove(nodeId); + return new MutexState(newHolder, term, newWaitList); + } + } + + public NodeId holder() { + return holder; + } + + public List waitList() { + return waitList; + } + + public long term() { + return term; + } + + private boolean contains(NodeId nodeId) { + return (nodeId.equals(holder) || waitList.contains(nodeId)); + } + + private MutexState(NodeId holder, long term, List waitList) { + this.holder = holder; + this.term = term; + this.waitList = Lists.newArrayList(waitList); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("holder", holder) + .add("term", term) + .add("waitList", waitList) + .toString(); + } + } + + private class InnerMutexTask implements MutexTask { + private final MutexTask task; + private final String mutexPath; + private final long term; + + public InnerMutexTask(String mutexPath, MutexTask task, long term) { + this.mutexPath = mutexPath; + this.term = term; + this.task = task; + } + + public long term() { + return term; + } + + @Override + public void start() { + log.debug("Starting execution for mutex task guarded by {}", mutexPath); + task.start(); + log.debug("Finished execution for mutex task guarded by {}", mutexPath); + } + + @Override + public void stop() { + log.debug("Stopping execution for mutex task guarded by {}", mutexPath); + task.stop(); + } + } +} \ No newline at end of file diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java index a294681e..f741b367 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java @@ -16,6 +16,17 @@ package org.onosproject.store.consistent.impl; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import net.kuujo.copycat.Task; +import net.kuujo.copycat.cluster.Cluster; +import net.kuujo.copycat.resource.ResourceState; +import org.onosproject.store.service.DatabaseUpdate; +import org.onosproject.store.service.Transaction; +import org.onosproject.store.service.Versioned; + import java.util.Collection; import java.util.List; import java.util.Map; @@ -28,18 +39,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.stream.Collectors; -import org.onosproject.store.service.DatabaseUpdate; -import org.onosproject.store.service.Transaction; -import org.onosproject.store.service.Versioned; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - -import net.kuujo.copycat.Task; -import net.kuujo.copycat.cluster.Cluster; -import net.kuujo.copycat.resource.ResourceState; import static com.google.common.base.Preconditions.checkState; /** @@ -100,10 +99,10 @@ public class PartitionedDatabase implements Database { return CompletableFuture.allOf(partitions .stream() .map(db -> db.counters() - .thenApply(m -> { - counters.putAll(m); - return null; - })) + .thenApply(m -> { + counters.putAll(m); + return null; + })) .toArray(CompletableFuture[]::new)) .thenApply(v -> counters); } @@ -113,9 +112,9 @@ public class PartitionedDatabase implements Database { checkState(isOpen.get(), DB_NOT_OPEN); AtomicInteger totalSize = new AtomicInteger(0); return CompletableFuture.allOf(partitions - .stream() - .map(p -> p.mapSize(mapName).thenApply(totalSize::addAndGet)) - .toArray(CompletableFuture[]::new)) + .stream() + .map(p -> p.mapSize(mapName).thenApply(totalSize::addAndGet)) + .toArray(CompletableFuture[]::new)) .thenApply(v -> totalSize.get()); } @@ -136,10 +135,10 @@ public class PartitionedDatabase implements Database { checkState(isOpen.get(), DB_NOT_OPEN); AtomicBoolean containsValue = new AtomicBoolean(false); return CompletableFuture.allOf(partitions - .stream() - .map(p -> p.mapContainsValue(mapName, value) - .thenApply(v -> containsValue.compareAndSet(false, v))) - .toArray(CompletableFuture[]::new)) + .stream() + .map(p -> p.mapContainsValue(mapName, value) + .thenApply(v -> containsValue.compareAndSet(false, v))) + .toArray(CompletableFuture[]::new)) .thenApply(v -> containsValue.get()); } @@ -196,9 +195,9 @@ public class PartitionedDatabase implements Database { checkState(isOpen.get(), DB_NOT_OPEN); Set>> entrySet = Sets.newConcurrentHashSet(); return CompletableFuture.allOf(partitions - .stream() - .map(p -> p.mapEntrySet(mapName).thenApply(entrySet::addAll)) - .toArray(CompletableFuture[]::new)) + .stream() + .map(p -> p.mapEntrySet(mapName).thenApply(entrySet::addAll)) + .toArray(CompletableFuture[]::new)) .thenApply(v -> entrySet); } @@ -220,6 +219,19 @@ public class PartitionedDatabase implements Database { return partitioner.getPartition(counterName, counterName).counterGetAndAdd(counterName, delta); } + @Override + public CompletableFuture counterSet(String counterName, long value) { + checkState(isOpen.get(), DB_NOT_OPEN); + return partitioner.getPartition(counterName, counterName).counterSet(counterName, value); + } + + @Override + public CompletableFuture counterCompareAndSet(String counterName, long expectedValue, long updateValue) { + checkState(isOpen.get(), DB_NOT_OPEN); + return partitioner.getPartition(counterName, counterName). + counterCompareAndSet(counterName, expectedValue, updateValue); + + } @Override public CompletableFuture queueSize(String queueName) { @@ -268,8 +280,8 @@ public class PartitionedDatabase implements Database { AtomicBoolean status = new AtomicBoolean(true); return CompletableFuture.allOf(subTransactions.entrySet() .stream() - .map(entry -> entry - .getKey() + .map(entry -> entry + .getKey() .prepare(entry.getValue()) .thenApply(v -> status.compareAndSet(true, v))) .toArray(CompletableFuture[]::new)) @@ -282,15 +294,15 @@ public class PartitionedDatabase implements Database { AtomicBoolean success = new AtomicBoolean(true); List> allUpdates = Lists.newArrayList(); return CompletableFuture.allOf(subTransactions.entrySet() - .stream() - .map(entry -> entry.getKey().commit(entry.getValue()) - .thenAccept(response -> { - success.set(success.get() && response.success()); - if (success.get()) { - allUpdates.addAll(response.updates()); - } - })) - .toArray(CompletableFuture[]::new)) + .stream() + .map(entry -> entry.getKey().commit(entry.getValue()) + .thenAccept(response -> { + success.set(success.get() && response.success()); + if (success.get()) { + allUpdates.addAll(response.updates()); + } + })) + .toArray(CompletableFuture[]::new)) .thenApply(v -> success.get() ? CommitResponse.success(allUpdates) : CommitResponse.failure()); } @@ -301,7 +313,7 @@ public class PartitionedDatabase implements Database { return CompletableFuture.allOf(subTransactions.entrySet() .stream() .map(entry -> entry.getKey().rollback(entry.getValue())) - .toArray(CompletableFuture[]::new)) + .toArray(CompletableFuture[]::new)) .thenApply(v -> true); } @@ -384,3 +396,4 @@ public class PartitionedDatabase implements Database { partitions.forEach(p -> p.unregisterConsumer(consumer)); } } + diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/EventuallyConsistentMapImpl.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/EventuallyConsistentMapImpl.java index 2859b62f..f1e0dbd4 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/EventuallyConsistentMapImpl.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/EventuallyConsistentMapImpl.java @@ -21,7 +21,6 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; - import org.apache.commons.lang3.tuple.Pair; import org.onlab.util.AbstractAccumulator; import org.onlab.util.KryoNamespace; @@ -33,18 +32,15 @@ import org.onosproject.store.Timestamp; import org.onosproject.store.cluster.messaging.ClusterCommunicationService; import org.onosproject.store.cluster.messaging.MessageSubject; import org.onosproject.store.impl.LogicalTimestamp; -import org.onosproject.store.service.WallClockTimestamp; import org.onosproject.store.serializers.KryoNamespaces; import org.onosproject.store.serializers.KryoSerializer; import org.onosproject.store.service.EventuallyConsistentMap; import org.onosproject.store.service.EventuallyConsistentMapEvent; import org.onosproject.store.service.EventuallyConsistentMapListener; +import org.onosproject.store.service.WallClockTimestamp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.PUT; -import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.REMOVE; - import java.util.Collection; import java.util.Collections; import java.util.List; @@ -67,6 +63,8 @@ import static com.google.common.base.Preconditions.checkState; import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; import static org.onlab.util.BoundedThreadPool.newFixedThreadPool; import static org.onlab.util.Tools.groupedThreads; +import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.PUT; +import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.REMOVE; /** * Distributed Map implementation which uses optimistic replication and gossip @@ -359,7 +357,7 @@ public class EventuallyConsistentMapImpl valueMatches = Objects.equals(value.get(), existing.get()); } if (existing == null) { - log.debug("ECMap Remove: Existing value for key {} is already null", k); + log.trace("ECMap Remove: Existing value for key {} is already null", k); } if (valueMatches) { if (existing == null) { @@ -523,7 +521,7 @@ public class EventuallyConsistentMapImpl return; } peers.forEach(node -> - senderPending.computeIfAbsent(node, unusedKey -> new EventAccumulator(node)).add(event) + senderPending.computeIfAbsent(node, unusedKey -> new EventAccumulator(node)).add(event) ); } @@ -576,8 +574,10 @@ public class EventuallyConsistentMapImpl return; } try { - log.debug("Received anti-entropy advertisement from {} for {} with {} entries in it", - mapName, ad.sender(), ad.digest().size()); + if (log.isTraceEnabled()) { + log.trace("Received anti-entropy advertisement from {} for {} with {} entries in it", + mapName, ad.sender(), ad.digest().size()); + } antiEntropyCheckLocalItems(ad).forEach(this::notifyListeners); if (!lightweightAntiEntropy) { @@ -675,4 +675,4 @@ public class EventuallyConsistentMapImpl }); } } -} \ No newline at end of file +} diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java index de7a3ac3..8cd63e7d 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java @@ -16,6 +16,7 @@ package org.onosproject.store.flow.impl; import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; @@ -57,6 +58,7 @@ import org.onosproject.net.flow.FlowRuleService; import org.onosproject.net.flow.FlowRuleStore; import org.onosproject.net.flow.FlowRuleStoreDelegate; import org.onosproject.net.flow.StoredFlowEntry; +import org.onosproject.net.flow.TableStatisticsEntry; import org.onosproject.store.AbstractStore; import org.onosproject.store.cluster.messaging.ClusterCommunicationService; import org.onosproject.store.cluster.messaging.ClusterMessage; @@ -64,9 +66,16 @@ import org.onosproject.store.cluster.messaging.ClusterMessageHandler; import org.onosproject.store.flow.ReplicaInfoEvent; import org.onosproject.store.flow.ReplicaInfoEventListener; import org.onosproject.store.flow.ReplicaInfoService; +import org.onosproject.store.impl.MastershipBasedTimestamp; +import org.onosproject.store.serializers.KryoNamespaces; import org.onosproject.store.serializers.KryoSerializer; import org.onosproject.store.serializers.StoreSerializer; import org.onosproject.store.serializers.custom.DistributedStoreSerializers; +import org.onosproject.store.service.EventuallyConsistentMap; +import org.onosproject.store.service.EventuallyConsistentMapEvent; +import org.onosproject.store.service.EventuallyConsistentMapListener; +import org.onosproject.store.service.StorageService; +import org.onosproject.store.service.WallClockTimestamp; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; @@ -151,6 +160,13 @@ public class NewDistributedFlowRuleStore private final ScheduledExecutorService backupSenderExecutor = Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/flow", "backup-sender")); + private EventuallyConsistentMap> deviceTableStats; + private final EventuallyConsistentMapListener> tableStatsListener = + new InternalTableStatsListener(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected StorageService storageService; + protected static final StoreSerializer SERIALIZER = new KryoSerializer() { @Override protected void setupKryoPool() { @@ -161,6 +177,11 @@ public class NewDistributedFlowRuleStore } }; + protected static final KryoNamespace.Builder SERIALIZER_BUILDER = KryoNamespace.newBuilder() + .register(KryoNamespaces.API) + .register(MastershipBasedTimestamp.class); + + private IdGenerator idGenerator; private NodeId local; @@ -186,6 +207,15 @@ public class NewDistributedFlowRuleStore TimeUnit.MILLISECONDS); } + deviceTableStats = storageService.>eventuallyConsistentMapBuilder() + .withName("onos-flow-table-stats") + .withSerializer(SERIALIZER_BUILDER) + .withAntiEntropyPeriod(5, TimeUnit.SECONDS) + .withTimestampProvider((k, v) -> new WallClockTimestamp()) + .withTombstonesDisabled() + .build(); + deviceTableStats.addListener(tableStatsListener); + logConfig("Started"); } @@ -197,6 +227,8 @@ public class NewDistributedFlowRuleStore } configService.unregisterProperties(getClass(), false); unregisterMessageHandlers(); + deviceTableStats.removeListener(tableStatsListener); + deviceTableStats.destroy(); messageHandlingExecutor.shutdownNow(); backupSenderExecutor.shutdownNow(); log.info("Stopped"); @@ -786,4 +818,36 @@ public class NewDistributedFlowRuleStore return backedupDevices; } } + + @Override + public FlowRuleEvent updateTableStatistics(DeviceId deviceId, + List tableStats) { + deviceTableStats.put(deviceId, tableStats); + return null; + } + + @Override + public Iterable getTableStatistics(DeviceId deviceId) { + NodeId master = mastershipService.getMasterFor(deviceId); + + if (master == null) { + log.debug("Failed to getTableStats: No master for {}", deviceId); + return Collections.emptyList(); + } + + List tableStats = deviceTableStats.get(deviceId); + if (tableStats == null) { + return Collections.emptyList(); + } + return ImmutableList.copyOf(tableStats); + } + + private class InternalTableStatsListener + implements EventuallyConsistentMapListener> { + @Override + public void event(EventuallyConsistentMapEvent> event) { + //TODO: Generate an event to listeners (do we need?) + } + } } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java index 97333ebf..a999ee7f 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java @@ -28,19 +28,11 @@ import org.apache.felix.scr.annotations.Service; import org.onlab.util.KryoNamespace; import org.onlab.util.NewConcurrentHashMap; import org.onosproject.cluster.ClusterService; -import org.onosproject.core.DefaultApplicationId; import org.onosproject.core.DefaultGroupId; import org.onosproject.core.GroupId; import org.onosproject.mastership.MastershipService; import org.onosproject.net.DeviceId; import org.onosproject.net.MastershipRole; -import org.onosproject.net.PortNumber; -import org.onosproject.net.flow.DefaultTrafficTreatment; -import org.onosproject.net.flow.FlowRule; -import org.onosproject.net.flow.instructions.Instructions; -import org.onosproject.net.flow.instructions.L0ModificationInstruction; -import org.onosproject.net.flow.instructions.L2ModificationInstruction; -import org.onosproject.net.flow.instructions.L3ModificationInstruction; import org.onosproject.net.group.DefaultGroup; import org.onosproject.net.group.DefaultGroupBucket; import org.onosproject.net.group.DefaultGroupDescription; @@ -61,9 +53,7 @@ import org.onosproject.net.group.StoredGroupEntry; import org.onosproject.store.AbstractStore; import org.onosproject.store.cluster.messaging.ClusterCommunicationService; import org.onosproject.store.service.MultiValuedTimestamp; -import org.onosproject.store.serializers.DeviceIdSerializer; import org.onosproject.store.serializers.KryoNamespaces; -import org.onosproject.store.serializers.URISerializer; import org.onosproject.store.service.EventuallyConsistentMap; import org.onosproject.store.service.EventuallyConsistentMapBuilder; import org.onosproject.store.service.EventuallyConsistentMapEvent; @@ -71,7 +61,6 @@ import org.onosproject.store.service.EventuallyConsistentMapListener; import org.onosproject.store.service.StorageService; import org.slf4j.Logger; -import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -139,9 +128,12 @@ public class DistributedGroupStore private final AtomicLong sequenceNumber = new AtomicLong(0); + private KryoNamespace clusterMsgSerializer; + @Activate public void activate() { kryoBuilder = new KryoNamespace.Builder() + .register(KryoNamespaces.API) .register(DefaultGroup.class, DefaultGroupBucket.class, DefaultGroupDescription.class, @@ -158,38 +150,9 @@ public class DistributedGroupStore GroupStoreKeyMapKey.class, GroupStoreIdMapKey.class, GroupStoreMapKey.class - ) - .register(new URISerializer(), URI.class) - .register(new DeviceIdSerializer(), DeviceId.class) - .register(PortNumber.class) - .register(DefaultApplicationId.class) - .register(DefaultTrafficTreatment.class, - Instructions.DropInstruction.class, - Instructions.OutputInstruction.class, - Instructions.GroupInstruction.class, - Instructions.TableTypeTransition.class, - FlowRule.Type.class, - L0ModificationInstruction.class, - L0ModificationInstruction.L0SubType.class, - L0ModificationInstruction.ModLambdaInstruction.class, - L2ModificationInstruction.class, - L2ModificationInstruction.L2SubType.class, - L2ModificationInstruction.ModEtherInstruction.class, - L2ModificationInstruction.PushHeaderInstructions.class, - L2ModificationInstruction.ModVlanIdInstruction.class, - L2ModificationInstruction.ModVlanPcpInstruction.class, - L2ModificationInstruction.ModMplsLabelInstruction.class, - L2ModificationInstruction.ModMplsTtlInstruction.class, - L3ModificationInstruction.class, - L3ModificationInstruction.L3SubType.class, - L3ModificationInstruction.ModIPInstruction.class, - L3ModificationInstruction.ModIPv6FlowLabelInstruction.class, - L3ModificationInstruction.ModTtlInstruction.class, - org.onlab.packet.MplsLabel.class - ) - .register(org.onosproject.cluster.NodeId.class) - .register(KryoNamespaces.BASIC) - .register(KryoNamespaces.MISC); + ); + + clusterMsgSerializer = kryoBuilder.build(); messageHandlingExecutor = Executors. newFixedThreadPool(MESSAGE_HANDLER_THREAD_POOL_SIZE, @@ -197,7 +160,7 @@ public class DistributedGroupStore "message-handlers")); clusterCommunicator.addSubscriber(GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST, - kryoBuilder.build()::deserialize, + clusterMsgSerializer::deserialize, this::process, messageHandlingExecutor); @@ -233,6 +196,7 @@ public class DistributedGroupStore @Deactivate public void deactivate() { + clusterCommunicator.removeSubscriber(GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST); groupStoreEntriesByKey.destroy(); auditPendingReqQueue.destroy(); log.info("Stopped"); @@ -313,8 +277,6 @@ public class DistributedGroupStore @Override public Iterable getGroups(DeviceId deviceId) { // flatten and make iterator unmodifiable - log.debug("getGroups: for device {} total number of groups {}", - deviceId, getGroupStoreKeyMap().values().size()); return FluentIterable.from(getGroupStoreKeyMap().values()) .filter(input -> input.deviceId().equals(deviceId)) .transform(input -> input); @@ -322,8 +284,6 @@ public class DistributedGroupStore private Iterable getStoredGroups(DeviceId deviceId) { // flatten and make iterator unmodifiable - log.debug("getGroups: for device {} total number of groups {}", - deviceId, getGroupStoreKeyMap().values().size()); return FluentIterable.from(getGroupStoreKeyMap().values()) .filter(input -> input.deviceId().equals(deviceId)); } @@ -411,7 +371,7 @@ public class DistributedGroupStore clusterCommunicator.unicast(groupOp, GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST, - m -> kryoBuilder.build().serialize(m), + clusterMsgSerializer::serialize, mastershipService.getMasterFor(groupDesc.deviceId())).whenComplete((result, error) -> { if (error != null) { log.warn("Failed to send request to master: {} to {}", @@ -609,7 +569,7 @@ public class DistributedGroupStore clusterCommunicator.unicast(groupOp, GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST, - m -> kryoBuilder.build().serialize(m), + clusterMsgSerializer::serialize, mastershipService.getMasterFor(deviceId)).whenComplete((result, error) -> { if (error != null) { log.warn("Failed to send request to master: {} to {}", @@ -741,7 +701,7 @@ public class DistributedGroupStore clusterCommunicator.unicast(groupOp, GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST, - m -> kryoBuilder.build().serialize(m), + clusterMsgSerializer::serialize, mastershipService.getMasterFor(deviceId)).whenComplete((result, error) -> { if (error != null) { log.warn("Failed to send request to master: {} to {}", diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java index d0b827cd..f9c96891 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java @@ -27,6 +27,7 @@ import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.RE import static org.slf4j.LoggerFactory.getLogger; import java.util.Collection; +import java.util.HashSet; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; @@ -67,7 +68,6 @@ import org.onosproject.store.service.StorageService; import org.slf4j.Logger; import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multimaps; import com.google.common.collect.SetMultimap; @@ -196,6 +196,35 @@ public class ECHostStore return host != null ? new HostEvent(HOST_REMOVED, host) : null; } + @Override + public HostEvent removeIp(HostId hostId, IpAddress ipAddress) { + DefaultHost host = hosts.compute(hostId, (id, existingHost) -> { + if (existingHost != null) { + checkState(Objects.equals(hostId.mac(), existingHost.mac()), + "Existing and new MAC addresses differ."); + checkState(Objects.equals(hostId.vlanId(), existingHost.vlan()), + "Existing and new VLANs differ."); + + Set addresses = existingHost.ipAddresses(); + if (addresses != null && addresses.contains(ipAddress)) { + addresses = new HashSet<>(existingHost.ipAddresses()); + addresses.remove(ipAddress); + return new DefaultHost(existingHost.providerId(), + hostId, + existingHost.mac(), + existingHost.vlan(), + existingHost.location(), + ImmutableSet.copyOf(addresses), + existingHost.annotations()); + } else { + return existingHost; + } + } + return null; + }); + return host != null ? new HostEvent(HOST_UPDATED, host) : null; + } + @Override public int getHostCount() { return hosts.size(); @@ -228,17 +257,23 @@ public class ECHostStore @Override public Set getConnectedHosts(ConnectPoint connectPoint) { - return ImmutableSet.copyOf(locations.get(connectPoint)); + synchronized (locations) { + return ImmutableSet.copyOf(locations.get(connectPoint)); + } } @Override public Set getConnectedHosts(DeviceId deviceId) { - return ImmutableMultimap.copyOf(locations) - .entries() - .stream() - .filter(entry -> entry.getKey().deviceId().equals(deviceId)) - .map(entry -> entry.getValue()) - .collect(Collectors.toSet()); + Set filtered; + synchronized (locations) { + filtered = locations + .entries() + .stream() + .filter(entry -> entry.getKey().deviceId().equals(deviceId)) + .map(entry -> entry.getValue()) + .collect(Collectors.toSet()); + } + return ImmutableSet.copyOf(filtered); } private Set filter(Collection collection, Predicate predicate) { diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java index fa3a0751..1e5db99c 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java @@ -193,7 +193,7 @@ public class GossipIntentStore private Collection getPeerNodes(Key key, IntentData data) { NodeId master = partitionService.getLeader(key); NodeId origin = (data != null) ? data.origin() : null; - if (master == null || origin == null) { + if (data != null && (master == null || origin == null)) { log.debug("Intent {} missing master and/or origin; master = {}, origin = {}", key, master, origin); } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/GossipLinkStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/GossipLinkStore.java index 105c77df..47aa85c5 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/GossipLinkStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/GossipLinkStore.java @@ -826,7 +826,7 @@ public class GossipLinkStore public void handle(ClusterMessage message) { log.trace("Received link event from peer: {}", message.sender()); - InternalLinkEvent event = (InternalLinkEvent) SERIALIZER.decode(message.payload()); + InternalLinkEvent event = SERIALIZER.decode(message.payload()); ProviderId providerId = event.providerId(); Timestamped linkDescription = event.linkDescription(); @@ -845,7 +845,7 @@ public class GossipLinkStore public void handle(ClusterMessage message) { log.trace("Received link removed event from peer: {}", message.sender()); - InternalLinkRemovedEvent event = (InternalLinkRemovedEvent) SERIALIZER.decode(message.payload()); + InternalLinkRemovedEvent event = SERIALIZER.decode(message.payload()); LinkKey linkKey = event.linkKey(); Timestamp timestamp = event.timestamp(); diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/packet/impl/DistributedPacketStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/packet/impl/DistributedPacketStore.java index d4c89c93..f0f3eb5e 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/packet/impl/DistributedPacketStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/packet/impl/DistributedPacketStore.java @@ -15,7 +15,9 @@ */ package org.onosproject.store.packet.impl; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -41,14 +43,13 @@ import org.onosproject.store.serializers.KryoSerializer; import org.onosproject.store.service.ConsistentMap; import org.onosproject.store.service.Serializer; import org.onosproject.store.service.StorageService; -import org.onosproject.store.service.Versioned; import org.slf4j.Logger; -import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; import static org.onlab.util.Tools.groupedThreads; import static org.slf4j.LoggerFactory.getLogger; @@ -117,6 +118,7 @@ public class DistributedPacketStore public void deactivate() { communicationService.removeSubscriber(PACKET_OUT_SUBJECT); messageHandlingExecutor.shutdown(); + tracker = null; log.info("Stopped"); } @@ -143,13 +145,13 @@ public class DistributedPacketStore } @Override - public boolean requestPackets(PacketRequest request) { - return tracker.add(request); + public void requestPackets(PacketRequest request) { + tracker.add(request); } @Override - public boolean cancelPackets(PacketRequest request) { - return tracker.remove(request); + public void cancelPackets(PacketRequest request) { + tracker.remove(request); } @Override @@ -169,33 +171,50 @@ public class DistributedPacketStore .build(); } - public boolean add(PacketRequest request) { - Versioned> old = requests.get(request.selector()); - if (old != null && old.value().contains(request)) { - return false; + public void add(PacketRequest request) { + AtomicBoolean firstRequest = new AtomicBoolean(false); + requests.compute(request.selector(), (s, existingRequests) -> { + if (existingRequests == null) { + firstRequest.set(true); + return ImmutableSet.of(request); + } else if (!existingRequests.contains(request)) { + return ImmutableSet.builder() + .addAll(existingRequests) + .add(request) + .build(); + } else { + return existingRequests; + } + }); + + if (firstRequest.get() && delegate != null) { + // The instance that makes the first request will push to all devices + delegate.requestPackets(request); } - // FIXME: add retry logic using a random delay - Set newSet = new HashSet<>(); - newSet.add(request); - if (old == null) { - return requests.putIfAbsent(request.selector(), newSet) == null; - } - newSet.addAll(old.value()); - return requests.replace(request.selector(), old.version(), newSet); } - public boolean remove(PacketRequest request) { - Versioned> old = requests.get(request.selector()); - if (old == null || !old.value().contains(request)) { - return false; - } - // FIXME: add retry logic using a random delay - Set newSet = new HashSet<>(old.value()); - newSet.remove(request); - if (newSet.isEmpty()) { - return requests.remove(request.selector(), old.version()); + public void remove(PacketRequest request) { + AtomicBoolean removedLast = new AtomicBoolean(false); + requests.computeIfPresent(request.selector(), (s, existingRequests) -> { + if (existingRequests.contains(request)) { + Set newRequests = Sets.newHashSet(existingRequests); + newRequests.remove(request); + if (newRequests.size() > 0) { + return ImmutableSet.copyOf(newRequests); + } else { + removedLast.set(true); + return null; + } + } else { + return existingRequests; + } + }); + + if (removedLast.get() && delegate != null) { + // The instance that removes the last request will remove from all devices + delegate.cancelPackets(request); } - return requests.replace(request.selector(), old.version(), newSet); + } public List requests() { @@ -204,6 +223,5 @@ public class DistributedPacketStore list.sort((o1, o2) -> o1.priority().priorityValue() - o2.priority().priorityValue()); return list; } - } } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentIntentSetMultimap.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentIntentSetMultimap.java new file mode 100644 index 00000000..87e67215 --- /dev/null +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentIntentSetMultimap.java @@ -0,0 +1,111 @@ +/* + * 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.store.resource.impl; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.intent.IntentId; +import org.onosproject.net.resource.device.IntentSetMultimap; +import org.onosproject.store.serializers.KryoNamespaces; +import org.onosproject.store.service.ConsistentMap; +import org.onosproject.store.service.Serializer; +import org.onosproject.store.service.StorageService; +import org.onosproject.store.service.Versioned; +import org.slf4j.Logger; + +import java.util.HashSet; +import java.util.Set; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * A collection that maps Intent IDs as keys to values as Intent IDs, + * where each key may associated with multiple values without duplication. + */ +@Component(immediate = true, enabled = true) +@Service +public class ConsistentIntentSetMultimap implements IntentSetMultimap { + private final Logger log = getLogger(getClass()); + + private static final String INTENT_MAPPING = "IntentMapping"; + + private static final Serializer SERIALIZER = Serializer.using(KryoNamespaces.API); + + private ConsistentMap> intentMapping; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected StorageService storageService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Activate + public void activate() { + intentMapping = storageService.>consistentMapBuilder() + .withName(INTENT_MAPPING) + .withSerializer(SERIALIZER) + .build(); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + + @Override + public Set getMapping(IntentId intentId) { + Versioned> result = intentMapping.get(intentId); + + if (result != null) { + return result.value(); + } + + return null; + } + + @Override + public boolean allocateMapping(IntentId keyIntentId, IntentId valIntentId) { + Versioned> versionedIntents = intentMapping.get(keyIntentId); + + if (versionedIntents == null) { + Set newSet = new HashSet<>(); + newSet.add(valIntentId); + intentMapping.put(keyIntentId, newSet); + } else { + versionedIntents.value().add(valIntentId); + } + + return true; + } + + @Override + public void releaseMapping(IntentId intentId) { + for (IntentId intent : intentMapping.keySet()) { + // TODO: optimize by checking for identical src & dst + Set mapping = intentMapping.get(intent).value(); + if (mapping.remove(intentId)) { + return; + } + } + } + +} diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java index 3a296353..11137aa2 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java @@ -40,7 +40,6 @@ import org.onosproject.net.Link; import org.onosproject.net.LinkKey; import org.onosproject.net.Port; import org.onosproject.net.intent.IntentId; -import org.onosproject.net.link.LinkService; import org.onosproject.net.resource.link.BandwidthResource; import org.onosproject.net.resource.link.BandwidthResourceAllocation; import org.onosproject.net.resource.link.LambdaResource; @@ -69,7 +68,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; 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.net.AnnotationKeys.BANDWIDTH; @@ -107,9 +105,6 @@ public class ConsistentLinkResourceStore extends @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected StorageService storageService; - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) - protected LinkService linkService; - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected DeviceService deviceService; @@ -139,29 +134,30 @@ public class ConsistentLinkResourceStore extends return storageService.transactionContextBuilder().build(); } - private Set getResourceCapacity(ResourceType type, Link link) { - if (type == ResourceType.BANDWIDTH) { - return ImmutableSet.of(getBandwidthResourceCapacity(link)); - } - if (type == ResourceType.LAMBDA) { - return getLambdaResourceCapacity(link); + private Set getResourceCapacity(ResourceType type, Link link) { + switch (type) { + case BANDWIDTH: + return ImmutableSet.of(getBandwidthResourceCapacity(link)); + case LAMBDA: + return getLambdaResourceCapacity(link); + case MPLS_LABEL: + return getMplsResourceCapacity(); + default: + return ImmutableSet.of(); } - if (type == ResourceType.MPLS_LABEL) { - return getMplsResourceCapacity(); - } - return ImmutableSet.of(); } - private Set getLambdaResourceCapacity(Link link) { - Set allocations = new HashSet<>(); + private Set getLambdaResourceCapacity(Link link) { Port port = deviceService.getPort(link.src().deviceId(), link.src().port()); - if (port instanceof OmsPort) { - OmsPort omsPort = (OmsPort) port; + if (!(port instanceof OmsPort)) { + return Collections.emptySet(); + } - // Assume fixed grid for now - for (int i = 0; i < omsPort.totalChannels(); i++) { - allocations.add(new LambdaResourceAllocation(LambdaResource.valueOf(i))); - } + OmsPort omsPort = (OmsPort) port; + Set allocations = new HashSet<>(); + // Assume fixed grid for now + for (int i = 0; i < omsPort.totalChannels(); i++) { + allocations.add(new LambdaResourceAllocation(LambdaResource.valueOf(i))); } return allocations; } @@ -170,26 +166,23 @@ public class ConsistentLinkResourceStore extends // if Link annotation exist, use them // if all fails, use DEFAULT_BANDWIDTH - BandwidthResource bandwidth = null; + BandwidthResource bandwidth = DEFAULT_BANDWIDTH; String strBw = link.annotations().value(BANDWIDTH); - if (strBw != null) { - try { - bandwidth = new BandwidthResource(Bandwidth.mbps(Double.parseDouble(strBw))); - } catch (NumberFormatException e) { - // do nothings - bandwidth = null; - } + if (strBw == null) { + return new BandwidthResourceAllocation(bandwidth); } - if (bandwidth == null) { - // fall back, use fixed default + try { + bandwidth = new BandwidthResource(Bandwidth.mbps(Double.parseDouble(strBw))); + } catch (NumberFormatException e) { + // do nothings, use default bandwidth bandwidth = DEFAULT_BANDWIDTH; } return new BandwidthResourceAllocation(bandwidth); } - private Set getMplsResourceCapacity() { - Set allocations = new HashSet<>(); + private Set getMplsResourceCapacity() { + Set allocations = new HashSet<>(); //Ignoring reserved labels of 0 through 15 for (int i = MIN_UNRESERVED_LABEL; i <= MAX_UNRESERVED_LABEL; i++) { allocations.add(new MplsLabelResourceAllocation(MplsLabel @@ -199,13 +192,11 @@ public class ConsistentLinkResourceStore extends return allocations; } - private Map> getResourceCapacity(Link link) { - Map> caps = new HashMap<>(); + private Map> getResourceCapacity(Link link) { + Map> caps = new HashMap<>(); for (ResourceType type : ResourceType.values()) { - Set cap = getResourceCapacity(type, link); - if (cap != null) { - caps.put(type, cap); - } + Set cap = getResourceCapacity(type, link); + caps.put(type, cap); } return caps; } @@ -216,106 +207,80 @@ public class ConsistentLinkResourceStore extends tx.begin(); try { - Map> freeResources = getFreeResourcesEx(tx, link); - Set allFree = new HashSet<>(); - freeResources.values().forEach(allFree::addAll); - return allFree; + Map> freeResources = getFreeResourcesEx(tx, link); + return freeResources.values().stream() + .flatMap(Collection::stream) + .collect(Collectors.toSet()); } finally { tx.abort(); } } - private Map> getFreeResourcesEx(TransactionContext tx, Link link) { + private Map> getFreeResourcesEx(TransactionContext tx, Link link) { checkNotNull(tx); checkNotNull(link); - Map> free = new HashMap<>(); - final Map> caps = getResourceCapacity(link); - final Iterable allocations = getAllocations(tx, link); + Map> free = new HashMap<>(); + final Map> caps = getResourceCapacity(link); + final List allocations = ImmutableList.copyOf(getAllocations(tx, link)); - for (ResourceType type : ResourceType.values()) { - // there should be class/category of resources + Set bw = caps.get(ResourceType.BANDWIDTH); + Set value = getFreeBandwidthResources(link, bw, allocations); + free.put(ResourceType.BANDWIDTH, value); - switch (type) { - case BANDWIDTH: - Set bw = caps.get(type); - if (bw == null || bw.isEmpty()) { - bw = Sets.newHashSet(new BandwidthResourceAllocation(EMPTY_BW)); - } + Set lmd = caps.get(ResourceType.LAMBDA); + Set freeL = getFreeResources(link, lmd, allocations, + LambdaResourceAllocation.class); + free.put(ResourceType.LAMBDA, freeL); - BandwidthResourceAllocation cap = (BandwidthResourceAllocation) bw.iterator().next(); - double freeBw = cap.bandwidth().toDouble(); - - // enumerate current allocations, subtracting resources - for (LinkResourceAllocations alloc : allocations) { - Set types = alloc.getResourceAllocation(link); - for (ResourceAllocation a : types) { - if (a instanceof BandwidthResourceAllocation) { - BandwidthResourceAllocation bwA = (BandwidthResourceAllocation) a; - freeBw -= bwA.bandwidth().toDouble(); - } - } - } + Set mpls = caps.get(ResourceType.MPLS_LABEL); + Set freeLabel = getFreeResources(link, mpls, allocations, + MplsLabelResourceAllocation.class); + free.put(ResourceType.MPLS_LABEL, freeLabel); - free.put(type, Sets.newHashSet( - new BandwidthResourceAllocation(new BandwidthResource(Bandwidth.bps(freeBw))))); - break; - case LAMBDA: - Set lmd = caps.get(type); - if (lmd == null || lmd.isEmpty()) { - // nothing left - break; - } - Set freeL = new HashSet<>(); - for (ResourceAllocation r : lmd) { - if (r instanceof LambdaResourceAllocation) { - freeL.add((LambdaResourceAllocation) r); - } - } - - // enumerate current allocations, removing resources - for (LinkResourceAllocations alloc : allocations) { - Set types = alloc.getResourceAllocation(link); - for (ResourceAllocation a : types) { - if (a instanceof LambdaResourceAllocation) { - freeL.remove(a); - } - } - } + return free; + } - free.put(type, freeL); - break; - case MPLS_LABEL: - Set mpls = caps.get(type); - if (mpls == null || mpls.isEmpty()) { - // nothing left - break; - } - Set freeLabel = new HashSet<>(); - for (ResourceAllocation r : mpls) { - if (r instanceof MplsLabelResourceAllocation) { - freeLabel.add((MplsLabelResourceAllocation) r); - } - } + private Set getFreeBandwidthResources(Link link, Set bw, + List allocations) { + if (bw == null || bw.isEmpty()) { + bw = Sets.newHashSet(new BandwidthResourceAllocation(EMPTY_BW)); + } - // enumerate current allocations, removing resources - for (LinkResourceAllocations alloc : allocations) { - Set types = alloc.getResourceAllocation(link); - for (ResourceAllocation a : types) { - if (a instanceof MplsLabelResourceAllocation) { - freeLabel.remove(a); - } - } - } + BandwidthResourceAllocation cap = (BandwidthResourceAllocation) bw.iterator().next(); + double freeBw = cap.bandwidth().toDouble(); + + // enumerate current allocations, subtracting resources + double allocatedBw = allocations.stream() + .flatMap(x -> x.getResourceAllocation(link).stream()) + .filter(x -> x instanceof BandwidthResourceAllocation) + .map(x -> (BandwidthResourceAllocation) x) + .mapToDouble(x -> x.bandwidth().toDouble()) + .sum(); + freeBw -= allocatedBw; + return Sets.newHashSet( + new BandwidthResourceAllocation(new BandwidthResource(Bandwidth.bps(freeBw)))); + } - free.put(type, freeLabel); - break; - default: - log.debug("unsupported ResourceType {}", type); - break; - } + private Set getFreeResources(Link link, + Set resources, + List allocations, + Class cls) { + if (resources == null || resources.isEmpty()) { + // nothing left + return Collections.emptySet(); } - return free; + Set freeL = resources.stream() + .filter(cls::isInstance) + .collect(Collectors.toSet()); + + // enumerate current allocations, removing resources + List allocated = allocations.stream() + .flatMap(x -> x.getResourceAllocation(link).stream()) + .filter(cls::isInstance) + .collect(Collectors.toList()); + freeL.removeAll(allocated); + return freeL; } @Override @@ -329,6 +294,9 @@ public class ConsistentLinkResourceStore extends intentAllocs.put(allocations.intentId(), allocations); allocations.links().forEach(link -> allocateLinkResource(tx, link, allocations)); tx.commit(); + } catch (TransactionException | ResourceAllocationException e) { + log.error("Exception thrown, rolling back", e); + tx.abort(); } catch (Exception e) { log.error("Exception thrown, rolling back", e); tx.abort(); @@ -340,15 +308,13 @@ public class ConsistentLinkResourceStore extends LinkResourceAllocations allocations) { // requested resources Set reqs = allocations.getResourceAllocation(link); - Map> available = getFreeResourcesEx(tx, link); + Map> available = getFreeResourcesEx(tx, link); for (ResourceAllocation req : reqs) { - Set avail = available.get(req.type()); + Set avail = available.get(req.type()); if (req instanceof BandwidthResourceAllocation) { // check if allocation should be accepted if (avail.isEmpty()) { - checkState(!avail.isEmpty(), - "There's no Bandwidth resource on %s?", - link); + throw new ResourceAllocationException(String.format("There's no Bandwidth resource on %s?", link)); } BandwidthResourceAllocation bw = (BandwidthResourceAllocation) avail.iterator().next(); double bwLeft = bw.bandwidth().toDouble(); @@ -395,12 +361,7 @@ public class ConsistentLinkResourceStore extends if (before == null) { List after = new ArrayList<>(); after.add(allocations); - before = linkAllocs.putIfAbsent(linkKey, after); - if (before != null) { - // concurrent allocation detected, retry transaction : is this needed? - log.warn("Concurrent Allocation, retrying"); - throw new TransactionException(); - } + linkAllocs.putIfAbsent(linkKey, after); } else { List after = new ArrayList<>(before.size() + 1); after.addAll(before); @@ -500,19 +461,18 @@ public class ConsistentLinkResourceStore extends checkNotNull(link); final LinkKey key = LinkKey.linkKey(link); TransactionalMap> linkAllocs = getLinkAllocs(tx); - List res = null; - res = linkAllocs.get(key); - if (res == null) { - res = linkAllocs.putIfAbsent(key, new ArrayList<>()); + List res = linkAllocs.get(key); + if (res != null) { + return res; + } - if (res == null) { - return Collections.emptyList(); - } else { - return res; - } + res = linkAllocs.putIfAbsent(key, new ArrayList<>()); + if (res == null) { + return Collections.emptyList(); + } else { + return res; } - return res; } } diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/statistic/impl/DistributedFlowStatisticStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/statistic/impl/DistributedFlowStatisticStore.java new file mode 100644 index 00000000..0cd4a831 --- /dev/null +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/statistic/impl/DistributedFlowStatisticStore.java @@ -0,0 +1,289 @@ +/* + * 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.store.statistic.impl; + +import com.google.common.base.Objects; +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; +import org.onlab.util.KryoNamespace; +import org.onlab.util.Tools; +import org.onosproject.cluster.ClusterService; +import org.onosproject.cluster.NodeId; +import org.onosproject.mastership.MastershipService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.FlowEntry; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.Instructions; +import org.onosproject.net.statistic.FlowStatisticStore; +import org.onosproject.store.cluster.messaging.ClusterCommunicationService; +import org.onosproject.store.serializers.KryoNamespaces; +import org.onosproject.store.serializers.KryoSerializer; +import org.slf4j.Logger; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.onlab.util.Tools.groupedThreads; +import static org.onosproject.store.statistic.impl.StatisticStoreMessageSubjects.GET_CURRENT; +import static org.onosproject.store.statistic.impl.StatisticStoreMessageSubjects.GET_PREVIOUS; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Maintains flow statistics using RPC calls to collect stats from remote instances + * on demand. + */ +@Component(immediate = true) +@Service +public class DistributedFlowStatisticStore implements FlowStatisticStore { + private final Logger log = getLogger(getClass()); + + // TODO: Make configurable. + private static final int MESSAGE_HANDLER_THREAD_POOL_SIZE = 4; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected MastershipService mastershipService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterCommunicationService clusterCommunicator; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterService clusterService; + + private Map> previous = + new ConcurrentHashMap<>(); + + private Map> current = + new ConcurrentHashMap<>(); + + protected static final KryoSerializer SERIALIZER = new KryoSerializer() { + @Override + protected void setupKryoPool() { + serializerPool = KryoNamespace.newBuilder() + .register(KryoNamespaces.API) + .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID) + // register this store specific classes here + .build(); + } + }; + + private NodeId local; + private ExecutorService messageHandlingExecutor; + + private static final long STATISTIC_STORE_TIMEOUT_MILLIS = 3000; + + @Activate + public void activate() { + local = clusterService.getLocalNode().id(); + + messageHandlingExecutor = Executors.newFixedThreadPool( + MESSAGE_HANDLER_THREAD_POOL_SIZE, + groupedThreads("onos/store/statistic", "message-handlers")); + + clusterCommunicator.addSubscriber( + GET_CURRENT, SERIALIZER::decode, this::getCurrentStatisticInternal, SERIALIZER::encode, + messageHandlingExecutor); + + clusterCommunicator.addSubscriber( + GET_CURRENT, SERIALIZER::decode, this::getPreviousStatisticInternal, SERIALIZER::encode, + messageHandlingExecutor); + + log.info("Started"); + } + + @Deactivate + public void deactivate() { + clusterCommunicator.removeSubscriber(GET_PREVIOUS); + clusterCommunicator.removeSubscriber(GET_CURRENT); + messageHandlingExecutor.shutdown(); + log.info("Stopped"); + } + + @Override + public synchronized void removeFlowStatistic(FlowRule rule) { + ConnectPoint cp = buildConnectPoint(rule); + if (cp == null) { + return; + } + + // remove this rule if present from current map + current.computeIfPresent(cp, (c, e) -> { e.remove(rule); return e; }); + + // remove this on if present from previous map + previous.computeIfPresent(cp, (c, e) -> { e.remove(rule); return e; }); + } + + @Override + public synchronized void addFlowStatistic(FlowEntry rule) { + ConnectPoint cp = buildConnectPoint(rule); + if (cp == null) { + return; + } + + // create one if absent and add this rule + current.putIfAbsent(cp, new HashSet<>()); + current.computeIfPresent(cp, (c, e) -> { e.add(rule); return e; }); + + // remove previous one if present + previous.computeIfPresent(cp, (c, e) -> { e.remove(rule); return e; }); + } + + public synchronized void updateFlowStatistic(FlowEntry rule) { + ConnectPoint cp = buildConnectPoint(rule); + if (cp == null) { + return; + } + + Set curr = current.get(cp); + if (curr == null) { + addFlowStatistic(rule); + } else { + Optional f = curr.stream().filter(c -> rule.equals(c)). + findAny(); + if (f.isPresent() && rule.bytes() < f.get().bytes()) { + log.debug("DistributedFlowStatisticStore:updateFlowStatistic():" + + " Invalid Flow Update! Will be removed!!" + + " curr flowId=" + Long.toHexString(rule.id().value()) + + ", prev flowId=" + Long.toHexString(f.get().id().value()) + + ", curr bytes=" + rule.bytes() + ", prev bytes=" + f.get().bytes() + + ", curr life=" + rule.life() + ", prev life=" + f.get().life() + + ", curr lastSeen=" + rule.lastSeen() + ", prev lastSeen=" + f.get().lastSeen()); + // something is wrong! invalid flow entry, so delete it + removeFlowStatistic(rule); + return; + } + Set prev = previous.get(cp); + if (prev == null) { + prev = new HashSet<>(); + previous.put(cp, prev); + } + + // previous one is exist + if (f.isPresent()) { + // remove old one and add new one + prev.remove(rule); + if (!prev.add(f.get())) { + log.debug("DistributedFlowStatisticStore:updateFlowStatistic():" + + " flowId={}, add failed into previous.", + Long.toHexString(rule.id().value())); + } + } + + // remove old one and add new one + curr.remove(rule); + if (!curr.add(rule)) { + log.debug("DistributedFlowStatisticStore:updateFlowStatistic():" + + " flowId={}, add failed into current.", + Long.toHexString(rule.id().value())); + } + } + } + + @Override + public Set getCurrentFlowStatistic(ConnectPoint connectPoint) { + final DeviceId deviceId = connectPoint.deviceId(); + + NodeId master = mastershipService.getMasterFor(deviceId); + if (master == null) { + log.warn("No master for {}", deviceId); + return Collections.emptySet(); + } + + if (Objects.equal(local, master)) { + return getCurrentStatisticInternal(connectPoint); + } else { + return Tools.futureGetOrElse(clusterCommunicator.sendAndReceive( + connectPoint, + GET_CURRENT, + SERIALIZER::encode, + SERIALIZER::decode, + master), + STATISTIC_STORE_TIMEOUT_MILLIS, + TimeUnit.MILLISECONDS, + Collections.emptySet()); + } + } + + private synchronized Set getCurrentStatisticInternal(ConnectPoint connectPoint) { + return current.get(connectPoint); + } + + @Override + public Set getPreviousFlowStatistic(ConnectPoint connectPoint) { + final DeviceId deviceId = connectPoint.deviceId(); + + NodeId master = mastershipService.getMasterFor(deviceId); + if (master == null) { + log.warn("No master for {}", deviceId); + return Collections.emptySet(); + } + + if (Objects.equal(local, master)) { + return getPreviousStatisticInternal(connectPoint); + } else { + return Tools.futureGetOrElse(clusterCommunicator.sendAndReceive( + connectPoint, + GET_PREVIOUS, + SERIALIZER::encode, + SERIALIZER::decode, + master), + STATISTIC_STORE_TIMEOUT_MILLIS, + TimeUnit.MILLISECONDS, + Collections.emptySet()); + } + } + + private synchronized Set getPreviousStatisticInternal(ConnectPoint connectPoint) { + return previous.get(connectPoint); + } + + private ConnectPoint buildConnectPoint(FlowRule rule) { + PortNumber port = getOutput(rule); + + if (port == null) { + return null; + } + ConnectPoint cp = new ConnectPoint(rule.deviceId(), port); + return cp; + } + + private PortNumber getOutput(FlowRule rule) { + for (Instruction i : rule.treatment().allInstructions()) { + if (i.type() == Instruction.Type.OUTPUT) { + Instructions.OutputInstruction out = (Instructions.OutputInstruction) i; + return out.port(); + } + if (i.type() == Instruction.Type.DROP) { + return PortNumber.P0; + } + } + return null; + } +} \ No newline at end of file diff --git a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java index 487fad9b..da4e3cc4 100644 --- a/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java +++ b/framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java @@ -21,6 +21,7 @@ import static org.onosproject.net.topology.TopologyEvent.Type.TOPOLOGY_CHANGED; import static org.slf4j.LoggerFactory.getLogger; import java.util.Collections; +import java.util.Map; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -40,6 +41,7 @@ import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.Link; import org.onosproject.net.Path; +import org.onosproject.net.DisjointPath; import org.onosproject.net.provider.ProviderId; import org.onosproject.net.topology.ClusterId; import org.onosproject.net.topology.DefaultGraphDescription; @@ -74,7 +76,6 @@ public class DistributedTopologyStore implements TopologyStore { private final Logger log = getLogger(getClass()); - private volatile DefaultTopology current = new DefaultTopology(ProviderId.NONE, new DefaultGraphDescription(0L, System.currentTimeMillis(), @@ -166,6 +167,29 @@ public class DistributedTopologyStore return defaultTopology(topology).getPaths(src, dst, weight); } + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst) { + return defaultTopology(topology).getDisjointPaths(src, dst); + } + + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight) { + return defaultTopology(topology).getDisjointPaths(src, dst, weight); + } + + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + Map riskProfile) { + return defaultTopology(topology).getDisjointPaths(src, dst, riskProfile); + } + + @Override + public Set getDisjointPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight, Map riskProfile) { + return defaultTopology(topology).getDisjointPaths(src, dst, weight, riskProfile); + } + @Override public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) { return defaultTopology(topology).isInfrastructure(connectPoint); diff --git a/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/host/impl/ECHostStoreTest.java b/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/host/impl/ECHostStoreTest.java new file mode 100644 index 00000000..a7077a81 --- /dev/null +++ b/framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/host/impl/ECHostStoreTest.java @@ -0,0 +1,95 @@ +/* + * 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.store.host.impl; + +import junit.framework.TestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onosproject.net.Host; +import org.onosproject.net.HostId; +import org.onosproject.net.HostLocation; +import org.onosproject.net.host.DefaultHostDescription; +import org.onosproject.net.host.HostDescription; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.store.Timestamp; +import org.onosproject.store.service.LogicalClockService; +import org.onosproject.store.service.TestStorageService; + +import java.util.HashSet; +import java.util.Set; + +/** + * Tests for the ECHostStore. + */ +public class ECHostStoreTest extends TestCase { + + private ECHostStore ecXHostStore; + + private static final HostId HOSTID = HostId.hostId(MacAddress.valueOf("1a:1a:1a:1a:1a:1a")); + + private static final IpAddress IP1 = IpAddress.valueOf("10.2.0.2"); + private static final IpAddress IP2 = IpAddress.valueOf("10.2.0.3"); + + private static final ProviderId PID = new ProviderId("of", "foo"); + + @Before + public void setUp() { + ecXHostStore = new ECHostStore(); + + ecXHostStore.storageService = new TestStorageService(); + ecXHostStore.clockService = new TestLogicalClockService(); + ecXHostStore.activate(); + } + + @After + public void tearDown() { + ecXHostStore.deactivate(); + } + + /** + * Tests the removeIp method call. + */ + @Test + public void testRemoveIp() { + Set ips = new HashSet<>(); + ips.add(IP1); + ips.add(IP2); + + HostDescription description = new DefaultHostDescription(HOSTID.mac(), + HOSTID.vlanId(), + HostLocation.NONE, + ips); + ecXHostStore.createOrUpdateHost(PID, HOSTID, description, false); + ecXHostStore.removeIp(HOSTID, IP1); + Host host = ecXHostStore.getHost(HOSTID); + + assertFalse(host.ipAddresses().contains(IP1)); + assertTrue(host.ipAddresses().contains(IP2)); + } + + /** + * Mocks the LogicalClockService class. + */ + class TestLogicalClockService implements LogicalClockService { + @Override + public Timestamp getTimestamp() { + return null; + } + } +} \ No newline at end of file diff --git a/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java index 66ee7be7..5b5056cb 100644 --- a/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java +++ b/framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java @@ -19,7 +19,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; - import org.onlab.packet.ChassisId; import org.onlab.packet.EthType; import org.onlab.packet.Ip4Address; @@ -85,11 +84,11 @@ import org.onosproject.net.device.PortStatistics; import org.onosproject.net.flow.CompletedBatchOperation; import org.onosproject.net.flow.DefaultFlowEntry; import org.onosproject.net.flow.DefaultFlowRule; +import org.onosproject.net.flow.DefaultTableStatisticsEntry; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.FlowEntry; import org.onosproject.net.flow.FlowId; -import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.FlowRuleBatchEntry; import org.onosproject.net.flow.FlowRuleBatchEvent; import org.onosproject.net.flow.FlowRuleBatchOperation; @@ -97,6 +96,7 @@ import org.onosproject.net.flow.FlowRuleBatchRequest; import org.onosproject.net.flow.FlowRuleEvent; import org.onosproject.net.flow.FlowRuleExtPayLoad; import org.onosproject.net.flow.StoredFlowEntry; +import org.onosproject.net.flow.TableStatisticsEntry; import org.onosproject.net.flow.criteria.Criterion; import org.onosproject.net.flow.criteria.EthCriterion; import org.onosproject.net.flow.criteria.EthTypeCriterion; @@ -118,7 +118,6 @@ import org.onosproject.net.flow.criteria.MetadataCriterion; import org.onosproject.net.flow.criteria.MplsCriterion; import org.onosproject.net.flow.criteria.OchSignalCriterion; import org.onosproject.net.flow.criteria.OchSignalTypeCriterion; -import org.onosproject.net.flow.criteria.OpticalSignalTypeCriterion; import org.onosproject.net.flow.criteria.PortCriterion; import org.onosproject.net.flow.criteria.SctpPortCriterion; import org.onosproject.net.flow.criteria.TcpPortCriterion; @@ -302,7 +301,6 @@ public final class KryoNamespaces { DefaultHostDescription.class, DefaultFlowEntry.class, StoredFlowEntry.class, - FlowRule.Type.class, DefaultFlowRule.class, DefaultFlowEntry.class, DefaultPacketRequest.class, @@ -339,11 +337,11 @@ public final class KryoNamespaces { IndexedLambdaCriterion.class, OchSignalCriterion.class, OchSignalTypeCriterion.class, - OpticalSignalTypeCriterion.class, Criterion.class, Criterion.Type.class, DefaultTrafficTreatment.class, Instructions.DropInstruction.class, + Instructions.NoActionInstruction.class, Instructions.OutputInstruction.class, Instructions.GroupInstruction.class, Instructions.TableTypeTransition.class, @@ -425,7 +423,9 @@ public final class KryoNamespaces { DefaultAnnotations.class, PortStatistics.class, DefaultPortStatistics.class, - IntentDomainId.class + IntentDomainId.class, + TableStatisticsEntry.class, + DefaultTableStatisticsEntry.class ) .register(new DefaultApplicationIdSerializer(), DefaultApplicationId.class) .register(new URISerializer(), URI.class) -- cgit