From 13d05bc8458758ee39cb829098241e89616717ee Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Wed, 9 Sep 2015 22:15:21 -0700 Subject: ONOS checkin based on commit tag e796610b1f721d02f9b0e213cf6f7790c10ecd60 Change-Id: Ife8810491034fe7becdba75dda20de4267bd15cd --- framework/src/onos/core/api/pom.xml | 68 + .../onosproject/app/ApplicationAdminService.java | 70 + .../onosproject/app/ApplicationDescription.java | 89 ++ .../java/org/onosproject/app/ApplicationEvent.java | 75 + .../org/onosproject/app/ApplicationException.java | 49 + .../org/onosproject/app/ApplicationListener.java | 24 + .../org/onosproject/app/ApplicationService.java | 70 + .../java/org/onosproject/app/ApplicationState.java | 33 + .../java/org/onosproject/app/ApplicationStore.java | 108 ++ .../onosproject/app/ApplicationStoreDelegate.java | 24 + .../app/DefaultApplicationDescription.java | 125 ++ .../java/org/onosproject/app/package-info.java | 20 + .../org/onosproject/cfg/ComponentConfigEvent.java | 74 + .../onosproject/cfg/ComponentConfigService.java | 74 + .../org/onosproject/cfg/ComponentConfigStore.java | 45 + .../cfg/ComponentConfigStoreDelegate.java | 24 + .../java/org/onosproject/cfg/ConfigProperty.java | 279 ++++ .../java/org/onosproject/cfg/package-info.java | 24 + .../onosproject/cluster/ClusterAdminService.java | 54 + .../cluster/ClusterDefinitionService.java | 32 + .../java/org/onosproject/cluster/ClusterEvent.java | 72 + .../onosproject/cluster/ClusterEventListener.java | 24 + .../org/onosproject/cluster/ClusterService.java | 68 + .../java/org/onosproject/cluster/ClusterStore.java | 84 + .../onosproject/cluster/ClusterStoreDelegate.java | 24 + .../org/onosproject/cluster/ControllerNode.java | 61 + .../cluster/ControllerNodeToNodeId.java | 45 + .../onosproject/cluster/DefaultControllerNode.java | 103 ++ .../java/org/onosproject/cluster/Leadership.java | 164 ++ .../org/onosproject/cluster/LeadershipEvent.java | 107 ++ .../cluster/LeadershipEventListener.java | 24 + .../org/onosproject/cluster/LeadershipService.java | 124 ++ .../main/java/org/onosproject/cluster/NodeId.java | 58 + .../java/org/onosproject/cluster/RoleInfo.java | 80 + .../java/org/onosproject/cluster/package-info.java | 20 + .../java/org/onosproject/codec/CodecContext.java | 50 + .../java/org/onosproject/codec/CodecService.java | 57 + .../main/java/org/onosproject/codec/JsonCodec.java | 115 ++ .../java/org/onosproject/codec/package-info.java | 20 + .../java/org/onosproject/core/Application.java | 87 + .../java/org/onosproject/core/ApplicationId.java | 36 + .../org/onosproject/core/ApplicationIdStore.java | 59 + .../java/org/onosproject/core/ApplicationRole.java | 38 + .../java/org/onosproject/core/CoreService.java | 83 + .../org/onosproject/core/DefaultApplication.java | 149 ++ .../org/onosproject/core/DefaultApplicationId.java | 81 + .../java/org/onosproject/core/DefaultGroupId.java | 66 + .../main/java/org/onosproject/core/GroupId.java | 31 + .../main/java/org/onosproject/core/IdBlock.java | 102 ++ .../java/org/onosproject/core/IdBlockStore.java | 31 + .../java/org/onosproject/core/IdGenerator.java | 31 + .../java/org/onosproject/core/MetricsHelper.java | 56 + .../onosproject/core/UnavailableIdException.java | 49 + .../main/java/org/onosproject/core/Version.java | 144 ++ .../java/org/onosproject/core/package-info.java | 20 + .../java/org/onosproject/event/AbstractEvent.java | 78 + .../onosproject/event/AbstractListenerManager.java | 58 + .../event/DefaultEventSinkRegistry.java | 62 + .../src/main/java/org/onosproject/event/Event.java | 45 + .../onosproject/event/EventDeliveryService.java | 38 + .../org/onosproject/event/EventDispatcher.java | 33 + .../java/org/onosproject/event/EventFilter.java | 34 + .../java/org/onosproject/event/EventListener.java | 30 + .../main/java/org/onosproject/event/EventSink.java | 36 + .../org/onosproject/event/EventSinkRegistry.java | 60 + .../org/onosproject/event/ListenerRegistry.java | 99 ++ .../org/onosproject/event/ListenerService.java | 38 + .../java/org/onosproject/event/package-info.java | 20 + .../mastership/MastershipAdminService.java | 45 + .../onosproject/mastership/MastershipEvent.java | 95 ++ .../onosproject/mastership/MastershipListener.java | 24 + .../onosproject/mastership/MastershipService.java | 101 ++ .../onosproject/mastership/MastershipStore.java | 125 ++ .../mastership/MastershipStoreDelegate.java | 24 + .../org/onosproject/mastership/MastershipTerm.java | 71 + .../mastership/MastershipTermService.java | 35 + .../org/onosproject/mastership/package-info.java | 20 + .../org/onosproject/net/AbstractAnnotated.java | 48 + .../org/onosproject/net/AbstractDescription.java | 49 + .../java/org/onosproject/net/AbstractElement.java | 45 + .../java/org/onosproject/net/AbstractModel.java | 49 + .../main/java/org/onosproject/net/Annotated.java | 30 + .../java/org/onosproject/net/AnnotationKeys.java | 145 ++ .../main/java/org/onosproject/net/Annotations.java | 40 + .../java/org/onosproject/net/AnnotationsUtil.java | 45 + .../java/org/onosproject/net/ChannelSpacing.java | 44 + .../java/org/onosproject/net/ConnectPoint.java | 175 ++ .../org/onosproject/net/DefaultAnnotations.java | 254 +++ .../java/org/onosproject/net/DefaultDevice.java | 142 ++ .../java/org/onosproject/net/DefaultEdgeLink.java | 96 ++ .../main/java/org/onosproject/net/DefaultHost.java | 117 ++ .../main/java/org/onosproject/net/DefaultLink.java | 131 ++ .../main/java/org/onosproject/net/DefaultPath.java | 105 ++ .../main/java/org/onosproject/net/DefaultPort.java | 127 ++ .../main/java/org/onosproject/net/Description.java | 26 + .../src/main/java/org/onosproject/net/Device.java | 83 + .../main/java/org/onosproject/net/DeviceId.java | 99 ++ .../main/java/org/onosproject/net/EdgeLink.java | 39 + .../src/main/java/org/onosproject/net/Element.java | 30 + .../main/java/org/onosproject/net/ElementId.java | 22 + .../main/java/org/onosproject/net/GridType.java | 29 + .../src/main/java/org/onosproject/net/Host.java | 68 + .../src/main/java/org/onosproject/net/HostId.java | 129 ++ .../java/org/onosproject/net/HostLocation.java | 67 + .../java/org/onosproject/net/IndexedLambda.java | 71 + .../main/java/org/onosproject/net/IpElementId.java | 61 + .../src/main/java/org/onosproject/net/Lambda.java | 45 + .../src/main/java/org/onosproject/net/Link.java | 114 ++ .../src/main/java/org/onosproject/net/LinkKey.java | 110 ++ .../java/org/onosproject/net/MastershipRole.java | 42 + .../org/onosproject/net/MutableAnnotations.java | 40 + .../main/java/org/onosproject/net/NetTools.java | 37 + .../java/org/onosproject/net/NetworkResource.java | 22 + .../src/main/java/org/onosproject/net/OchPort.java | 115 ++ .../main/java/org/onosproject/net/OchSignal.java | 176 +++ .../java/org/onosproject/net/OchSignalType.java | 32 + .../main/java/org/onosproject/net/OduCltPort.java | 97 ++ .../java/org/onosproject/net/OduSignalType.java | 33 + .../src/main/java/org/onosproject/net/OmsPort.java | 131 ++ .../src/main/java/org/onosproject/net/Path.java | 42 + .../src/main/java/org/onosproject/net/Port.java | 100 ++ .../main/java/org/onosproject/net/PortNumber.java | 182 +++ .../main/java/org/onosproject/net/Provided.java | 32 + .../org/onosproject/net/SparseAnnotations.java | 44 + .../onosproject/net/behaviour/BridgeConfig.java | 87 + .../net/behaviour/BridgeDescription.java | 46 + .../org/onosproject/net/behaviour/BridgeName.java | 78 + .../net/behaviour/ControllerConfig.java | 39 + .../onosproject/net/behaviour/ControllerInfo.java | 38 + .../net/behaviour/DefaultBridgeDescription.java | 87 + .../net/behaviour/DefaultNextGroup.java | 33 + .../net/behaviour/DefaultTunnelDescription.java | 87 + .../net/behaviour/IpTunnelEndPoint.java | 80 + .../org/onosproject/net/behaviour/MplsQuery.java | 35 + .../org/onosproject/net/behaviour/NextGroup.java | 30 + .../org/onosproject/net/behaviour/Pipeliner.java | 57 + .../net/behaviour/PipelinerContext.java | 41 + .../org/onosproject/net/behaviour/PortAdmin.java | 33 + .../org/onosproject/net/behaviour/PortConfig.java | 40 + .../org/onosproject/net/behaviour/QueueConfig.java | 56 + .../org/onosproject/net/behaviour/QueueInfo.java | 56 + .../onosproject/net/behaviour/TunnelConfig.java | 55 + .../net/behaviour/TunnelDescription.java | 86 + .../onosproject/net/behaviour/TunnelEndPoint.java | 28 + .../org/onosproject/net/behaviour/TunnelName.java | 79 + .../org/onosproject/net/behaviour/VlanQuery.java | 35 + .../onosproject/net/behaviour/package-info.java | 21 + .../java/org/onosproject/net/config/Config.java | 312 ++++ .../net/config/ConfigApplyDelegate.java | 33 + .../org/onosproject/net/config/ConfigFactory.java | 122 ++ .../org/onosproject/net/config/ConfigOperator.java | 31 + .../onosproject/net/config/NetworkConfigEvent.java | 92 ++ .../net/config/NetworkConfigListener.java | 24 + .../net/config/NetworkConfigRegistry.java | 75 + .../net/config/NetworkConfigService.java | 146 ++ .../onosproject/net/config/NetworkConfigStore.java | 130 ++ .../net/config/NetworkConfigStoreDelegate.java | 24 + .../org/onosproject/net/config/SubjectFactory.java | 75 + .../net/config/basics/AllowedEntityConfig.java | 49 + .../net/config/basics/BasicDeviceConfig.java | 70 + .../net/config/basics/BasicElementConfig.java | 130 ++ .../net/config/basics/BasicHostConfig.java | 27 + .../net/config/basics/BasicLinkConfig.java | 90 ++ .../net/config/basics/OpticalPortConfig.java | 175 ++ .../net/config/basics/SubjectFactories.java | 93 ++ .../net/config/basics/package-info.java | 20 + .../org/onosproject/net/config/package-info.java | 20 + .../net/device/DefaultDeviceDescription.java | 145 ++ .../net/device/DefaultPortDescription.java | 120 ++ .../net/device/DefaultPortStatistics.java | 346 ++++ .../onosproject/net/device/DeviceAdminService.java | 34 + .../onosproject/net/device/DeviceClockService.java | 41 + .../onosproject/net/device/DeviceDescription.java | 80 + .../org/onosproject/net/device/DeviceEvent.java | 141 ++ .../org/onosproject/net/device/DeviceListener.java | 24 + .../org/onosproject/net/device/DeviceProvider.java | 57 + .../net/device/DeviceProviderRegistry.java | 25 + .../net/device/DeviceProviderService.java | 82 + .../org/onosproject/net/device/DeviceService.java | 132 ++ .../org/onosproject/net/device/DeviceStore.java | 170 ++ .../net/device/DeviceStoreDelegate.java | 24 + .../onosproject/net/device/OchPortDescription.java | 111 ++ .../net/device/OduCltPortDescription.java | 77 + .../onosproject/net/device/OmsPortDescription.java | 109 ++ .../onosproject/net/device/PortDescription.java | 56 + .../org/onosproject/net/device/PortStatistics.java | 100 ++ .../org/onosproject/net/device/package-info.java | 20 + .../onosproject/net/driver/AbstractBehaviour.java | 37 + .../net/driver/AbstractHandlerBehaviour.java | 38 + .../java/org/onosproject/net/driver/Behaviour.java | 39 + .../org/onosproject/net/driver/DefaultDriver.java | 214 +++ .../onosproject/net/driver/DefaultDriverData.java | 100 ++ .../net/driver/DefaultDriverHandler.java | 67 + .../net/driver/DefaultDriverProvider.java | 86 + .../net/driver/DefaultDriverProviderService.java | 23 + .../java/org/onosproject/net/driver/Driver.java | 132 ++ .../onosproject/net/driver/DriverAdminService.java | 46 + .../org/onosproject/net/driver/DriverConnect.java | 36 + .../org/onosproject/net/driver/DriverData.java | 50 + .../org/onosproject/net/driver/DriverHandler.java | 57 + .../org/onosproject/net/driver/DriverProvider.java | 34 + .../org/onosproject/net/driver/DriverResolver.java | 34 + .../org/onosproject/net/driver/DriverService.java | 83 + .../onosproject/net/driver/HandlerBehaviour.java | 38 + .../onosproject/net/driver/XmlDriverLoader.java | 176 +++ .../org/onosproject/net/driver/package-info.java | 68 + .../org/onosproject/net/edge/EdgePortEvent.java | 59 + .../org/onosproject/net/edge/EdgePortListener.java | 24 + .../org/onosproject/net/edge/EdgePortService.java | 75 + .../org/onosproject/net/edge/package-info.java | 20 + .../org/onosproject/net/flow/BatchOperation.java | 128 ++ .../onosproject/net/flow/BatchOperationEntry.java | 90 ++ .../onosproject/net/flow/BatchOperationResult.java | 38 + .../net/flow/CompletedBatchOperation.java | 96 ++ .../org/onosproject/net/flow/DefaultFlowEntry.java | 137 ++ .../org/onosproject/net/flow/DefaultFlowRule.java | 390 +++++ .../net/flow/DefaultTrafficSelector.java | 365 +++++ .../net/flow/DefaultTrafficTreatment.java | 479 ++++++ .../java/org/onosproject/net/flow/FlowEntry.java | 102 ++ .../main/java/org/onosproject/net/flow/FlowId.java | 58 + .../java/org/onosproject/net/flow/FlowRule.java | 265 ++++ .../onosproject/net/flow/FlowRuleBatchEntry.java | 49 + .../onosproject/net/flow/FlowRuleBatchEvent.java | 116 ++ .../net/flow/FlowRuleBatchOperation.java | 54 + .../onosproject/net/flow/FlowRuleBatchRequest.java | 59 + .../org/onosproject/net/flow/FlowRuleEvent.java | 78 + .../onosproject/net/flow/FlowRuleExtPayLoad.java | 67 + .../org/onosproject/net/flow/FlowRuleListener.java | 24 + .../onosproject/net/flow/FlowRuleOperation.java | 67 + .../onosproject/net/flow/FlowRuleOperations.java | 181 +++ .../net/flow/FlowRuleOperationsContext.java | 28 + .../org/onosproject/net/flow/FlowRuleProvider.java | 58 + .../net/flow/FlowRuleProviderRegistry.java | 25 + .../net/flow/FlowRuleProviderService.java | 52 + .../org/onosproject/net/flow/FlowRuleService.java | 107 ++ .../org/onosproject/net/flow/FlowRuleStore.java | 96 ++ .../net/flow/FlowRuleStoreDelegate.java | 24 + .../org/onosproject/net/flow/StoredFlowEntry.java | 50 + .../org/onosproject/net/flow/TrafficSelector.java | 420 +++++ .../org/onosproject/net/flow/TrafficTreatment.java | 431 +++++ .../java/org/onosproject/net/flow/Treatment.java | 36 + .../onosproject/net/flow/criteria/Criteria.java | 527 ++++++ .../onosproject/net/flow/criteria/Criterion.java | 181 +++ .../net/flow/criteria/EthCriterion.java | 80 + .../net/flow/criteria/EthTypeCriterion.java | 89 ++ .../onosproject/net/flow/criteria/IPCriterion.java | 80 + .../net/flow/criteria/IPDscpCriterion.java | 76 + .../net/flow/criteria/IPEcnCriterion.java | 76 + .../net/flow/criteria/IPProtocolCriterion.java | 76 + .../flow/criteria/IPv6ExthdrFlagsCriterion.java | 78 + .../net/flow/criteria/IPv6FlowLabelCriterion.java | 76 + .../criteria/IPv6NDLinkLayerAddressCriterion.java | 81 + .../criteria/IPv6NDTargetAddressCriterion.java | 77 + .../net/flow/criteria/IcmpCodeCriterion.java | 75 + .../net/flow/criteria/IcmpTypeCriterion.java | 75 + .../net/flow/criteria/Icmpv6CodeCriterion.java | 75 + .../net/flow/criteria/Icmpv6TypeCriterion.java | 75 + .../net/flow/criteria/IndexedLambdaCriterion.java | 80 + .../net/flow/criteria/LambdaCriterion.java | 80 + .../net/flow/criteria/MetadataCriterion.java | 75 + .../net/flow/criteria/MplsBosCriterion.java | 48 + .../net/flow/criteria/MplsCriterion.java | 67 + .../net/flow/criteria/OchSignalCriterion.java | 81 + .../net/flow/criteria/OchSignalTypeCriterion.java | 78 + .../flow/criteria/OpticalSignalTypeCriterion.java | 83 + .../net/flow/criteria/PortCriterion.java | 80 + .../net/flow/criteria/SctpPortCriterion.java | 80 + .../net/flow/criteria/TcpPortCriterion.java | 80 + .../net/flow/criteria/TunnelIdCriterion.java | 74 + .../net/flow/criteria/UdpPortCriterion.java | 80 + .../net/flow/criteria/VlanIdCriterion.java | 76 + .../net/flow/criteria/VlanPcpCriterion.java | 75 + .../net/flow/criteria/package-info.java | 20 + .../net/flow/instructions/Instruction.java | 84 + .../net/flow/instructions/Instructions.java | 742 +++++++++ .../instructions/L0ModificationInstruction.java | 139 ++ .../instructions/L2ModificationInstruction.java | 517 ++++++ .../instructions/L3ModificationInstruction.java | 231 +++ .../instructions/L4ModificationInstruction.java | 114 ++ .../net/flow/instructions/package-info.java | 20 + .../org/onosproject/net/flow/package-info.java | 26 + .../flowobjective/DefaultFilteringObjective.java | 239 +++ .../flowobjective/DefaultForwardingObjective.java | 241 +++ .../net/flowobjective/DefaultNextObjective.java | 222 +++ .../net/flowobjective/FilteringObjective.java | 158 ++ .../net/flowobjective/FlowObjectiveService.java | 65 + .../net/flowobjective/FlowObjectiveStore.java | 50 + .../flowobjective/FlowObjectiveStoreDelegate.java | 26 + .../net/flowobjective/ForwardingObjective.java | 158 ++ .../net/flowobjective/NextObjective.java | 167 ++ .../onosproject/net/flowobjective/Objective.java | 134 ++ .../net/flowobjective/ObjectiveContext.java | 47 + .../net/flowobjective/ObjectiveError.java | 60 + .../net/flowobjective/ObjectiveEvent.java | 64 + .../net/flowobjective/package-info.java | 22 + .../org/onosproject/net/group/DefaultGroup.java | 229 +++ .../onosproject/net/group/DefaultGroupBucket.java | 252 +++ .../net/group/DefaultGroupDescription.java | 204 +++ .../org/onosproject/net/group/DefaultGroupKey.java | 55 + .../main/java/org/onosproject/net/group/Group.java | 99 ++ .../org/onosproject/net/group/GroupBucket.java | 80 + .../org/onosproject/net/group/GroupBuckets.java | 76 + .../onosproject/net/group/GroupDescription.java | 91 ++ .../java/org/onosproject/net/group/GroupEvent.java | 99 ++ .../java/org/onosproject/net/group/GroupKey.java | 31 + .../org/onosproject/net/group/GroupListener.java | 24 + .../org/onosproject/net/group/GroupOperation.java | 181 +++ .../org/onosproject/net/group/GroupOperations.java | 50 + .../org/onosproject/net/group/GroupProvider.java | 37 + .../net/group/GroupProviderRegistry.java | 25 + .../net/group/GroupProviderService.java | 47 + .../org/onosproject/net/group/GroupService.java | 139 ++ .../java/org/onosproject/net/group/GroupStore.java | 175 ++ .../onosproject/net/group/GroupStoreDelegate.java | 24 + .../net/group/StoredGroupBucketEntry.java | 37 + .../onosproject/net/group/StoredGroupEntry.java | 75 + .../org/onosproject/net/group/package-info.java | 20 + .../net/host/DefaultHostDescription.java | 122 ++ .../org/onosproject/net/host/HostAdminService.java | 66 + .../org/onosproject/net/host/HostDescription.java | 58 + .../java/org/onosproject/net/host/HostEvent.java | 73 + .../org/onosproject/net/host/HostListener.java | 24 + .../org/onosproject/net/host/HostProvider.java | 37 + .../onosproject/net/host/HostProviderRegistry.java | 25 + .../onosproject/net/host/HostProviderService.java | 42 + .../java/org/onosproject/net/host/HostService.java | 146 ++ .../java/org/onosproject/net/host/HostStore.java | 167 ++ .../onosproject/net/host/HostStoreDelegate.java | 24 + .../onosproject/net/host/InterfaceIpAddress.java | 192 +++ .../org/onosproject/net/host/PortAddresses.java | 127 ++ .../org/onosproject/net/host/package-info.java | 20 + .../onosproject/net/intent/ConnectivityIntent.java | 187 +++ .../org/onosproject/net/intent/Constraint.java | 53 + .../org/onosproject/net/intent/FlowRuleIntent.java | 110 ++ .../onosproject/net/intent/HostToHostIntent.java | 194 +++ .../java/org/onosproject/net/intent/Intent.java | 218 +++ .../net/intent/IntentBatchDelegate.java | 35 + .../onosproject/net/intent/IntentClockService.java | 34 + .../org/onosproject/net/intent/IntentCompiler.java | 44 + .../org/onosproject/net/intent/IntentData.java | 327 ++++ .../org/onosproject/net/intent/IntentEvent.java | 146 ++ .../onosproject/net/intent/IntentException.java | 53 + .../net/intent/IntentExtensionService.java | 51 + .../java/org/onosproject/net/intent/IntentId.java | 87 + .../org/onosproject/net/intent/IntentListener.java | 26 + .../onosproject/net/intent/IntentOperation.java | 124 ++ .../org/onosproject/net/intent/IntentService.java | 123 ++ .../org/onosproject/net/intent/IntentState.java | 117 ++ .../org/onosproject/net/intent/IntentStore.java | 143 ++ .../net/intent/IntentStoreDelegate.java | 42 + .../main/java/org/onosproject/net/intent/Key.java | 163 ++ .../net/intent/LinkCollectionIntent.java | 241 +++ .../org/onosproject/net/intent/MplsIntent.java | 261 +++ .../org/onosproject/net/intent/MplsPathIntent.java | 167 ++ .../net/intent/MultiPointToSinglePointIntent.java | 223 +++ .../net/intent/OpticalCircuitIntent.java | 219 +++ .../net/intent/OpticalConnectivityIntent.java | 223 +++ .../onosproject/net/intent/OpticalPathIntent.java | 234 +++ .../org/onosproject/net/intent/PartitionEvent.java | 35 + .../net/intent/PartitionEventListener.java | 26 + .../onosproject/net/intent/PartitionService.java | 48 + .../org/onosproject/net/intent/PathIntent.java | 202 +++ .../onosproject/net/intent/PointToPointIntent.java | 215 +++ .../net/intent/SinglePointToMultiPointIntent.java | 219 +++ .../onosproject/net/intent/TwoWayP2PIntent.java | 195 +++ .../intent/constraint/AnnotationConstraint.java | 113 ++ .../constraint/AsymmetricPathConstraint.java | 64 + .../net/intent/constraint/BandwidthConstraint.java | 96 ++ .../net/intent/constraint/BooleanConstraint.java | 64 + .../net/intent/constraint/LambdaConstraint.java | 91 ++ .../net/intent/constraint/LatencyConstraint.java | 93 ++ .../net/intent/constraint/LinkTypeConstraint.java | 108 ++ .../net/intent/constraint/ObstacleConstraint.java | 92 ++ .../constraint/PartialFailureConstraint.java | 49 + .../net/intent/constraint/WaypointConstraint.java | 117 ++ .../net/intent/constraint/package-info.java | 20 + .../org/onosproject/net/intent/package-info.java | 83 + .../net/link/DefaultLinkDescription.java | 73 + .../org/onosproject/net/link/LinkAdminService.java | 50 + .../org/onosproject/net/link/LinkDescription.java | 49 + .../java/org/onosproject/net/link/LinkEvent.java | 68 + .../org/onosproject/net/link/LinkListener.java | 24 + .../org/onosproject/net/link/LinkProvider.java | 25 + .../onosproject/net/link/LinkProviderRegistry.java | 25 + .../onosproject/net/link/LinkProviderService.java | 57 + .../java/org/onosproject/net/link/LinkService.java | 116 ++ .../java/org/onosproject/net/link/LinkStore.java | 117 ++ .../onosproject/net/link/LinkStoreDelegate.java | 24 + .../org/onosproject/net/link/package-info.java | 20 + .../main/java/org/onosproject/net/meter/Band.java | 133 ++ .../java/org/onosproject/net/meter/BandEntry.java | 37 + .../org/onosproject/net/meter/DefaultBand.java | 136 ++ .../org/onosproject/net/meter/DefaultMeter.java | 233 +++ .../onosproject/net/meter/DefaultMeterRequest.java | 171 ++ .../main/java/org/onosproject/net/meter/Meter.java | 179 +++ .../org/onosproject/net/meter/MeterContext.java | 38 + .../java/org/onosproject/net/meter/MeterEntry.java | 57 + .../java/org/onosproject/net/meter/MeterEvent.java | 62 + .../org/onosproject/net/meter/MeterFailReason.java | 89 ++ .../java/org/onosproject/net/meter/MeterId.java | 78 + .../org/onosproject/net/meter/MeterListener.java | 24 + .../org/onosproject/net/meter/MeterOperation.java | 88 ++ .../org/onosproject/net/meter/MeterOperations.java | 50 + .../org/onosproject/net/meter/MeterProvider.java | 48 + .../net/meter/MeterProviderRegistry.java | 27 + .../net/meter/MeterProviderService.java | 49 + .../org/onosproject/net/meter/MeterRequest.java | 147 ++ .../org/onosproject/net/meter/MeterService.java | 61 + .../java/org/onosproject/net/meter/MeterState.java | 43 + .../java/org/onosproject/net/meter/MeterStore.java | 90 ++ .../onosproject/net/meter/MeterStoreDelegate.java | 24 + .../onosproject/net/meter/MeterStoreResult.java | 66 + .../org/onosproject/net/meter/package-info.java | 20 + .../net/newresource/ResourceAdminService.java | 75 + .../net/newresource/ResourceAllocation.java | 94 ++ .../net/newresource/ResourceConsumer.java | 25 + .../onosproject/net/newresource/ResourcePath.java | 146 ++ .../net/newresource/ResourceService.java | 155 ++ .../onosproject/net/newresource/ResourceStore.java | 90 ++ .../onosproject/net/newresource/package-info.java | 21 + .../java/org/onosproject/net/package-info.java | 20 + .../net/packet/DefaultInboundPacket.java | 91 ++ .../net/packet/DefaultOutboundPacket.java | 89 ++ .../net/packet/DefaultPacketContext.java | 95 ++ .../net/packet/DefaultPacketRequest.java | 84 + .../org/onosproject/net/packet/InboundPacket.java | 50 + .../org/onosproject/net/packet/OutboundPacket.java | 51 + .../org/onosproject/net/packet/PacketContext.java | 73 + .../org/onosproject/net/packet/PacketEvent.java | 56 + .../org/onosproject/net/packet/PacketPriority.java | 53 + .../onosproject/net/packet/PacketProcessor.java | 83 + .../org/onosproject/net/packet/PacketProvider.java | 32 + .../net/packet/PacketProviderRegistry.java | 25 + .../net/packet/PacketProviderService.java | 33 + .../org/onosproject/net/packet/PacketRequest.java | 47 + .../org/onosproject/net/packet/PacketService.java | 79 + .../org/onosproject/net/packet/PacketStore.java | 59 + .../net/packet/PacketStoreDelegate.java | 24 + .../org/onosproject/net/packet/package-info.java | 21 + .../provider/AbstractListenerProviderRegistry.java | 66 + .../onosproject/net/provider/AbstractProvider.java | 39 + .../net/provider/AbstractProviderRegistry.java | 111 ++ .../net/provider/AbstractProviderService.java | 61 + .../org/onosproject/net/provider/Provider.java | 30 + .../org/onosproject/net/provider/ProviderId.java | 135 ++ .../onosproject/net/provider/ProviderRegistry.java | 57 + .../onosproject/net/provider/ProviderService.java | 33 + .../org/onosproject/net/provider/package-info.java | 20 + .../onosproject/net/proxyarp/ProxyArpService.java | 64 + .../onosproject/net/proxyarp/ProxyArpStore.java | 45 + .../net/proxyarp/ProxyArpStoreDelegate.java | 35 + .../org/onosproject/net/proxyarp/package-info.java | 20 + .../net/resource/ResourceAllocation.java | 31 + .../net/resource/ResourceAllocationException.java | 36 + .../net/resource/ResourceException.java | 51 + .../org/onosproject/net/resource/ResourceId.java | 25 + .../onosproject/net/resource/ResourceRequest.java | 32 + .../org/onosproject/net/resource/ResourceType.java | 39 + .../net/resource/device/DeviceResourceService.java | 85 + .../net/resource/device/DeviceResourceStore.java | 89 ++ .../net/resource/device/package-info.java | 20 + .../net/resource/link/BandwidthResource.java | 72 + .../resource/link/BandwidthResourceAllocation.java | 77 + .../resource/link/BandwidthResourceRequest.java | 77 + .../link/DefaultLinkResourceAllocations.java | 112 ++ .../resource/link/DefaultLinkResourceRequest.java | 186 +++ .../net/resource/link/LambdaResource.java | 93 ++ .../resource/link/LambdaResourceAllocation.java | 77 + .../net/resource/link/LambdaResourceRequest.java | 37 + .../net/resource/link/LinkResource.java | 22 + .../net/resource/link/LinkResourceAllocations.java | 59 + .../net/resource/link/LinkResourceEvent.java | 48 + .../net/resource/link/LinkResourceListener.java | 24 + .../net/resource/link/LinkResourceRequest.java | 93 ++ .../net/resource/link/LinkResourceService.java | 95 ++ .../net/resource/link/LinkResourceStore.java | 73 + .../resource/link/LinkResourceStoreDelegate.java | 24 + .../net/resource/link/LinkResources.java | 63 + .../onosproject/net/resource/link/MplsLabel.java | 75 + .../resource/link/MplsLabelResourceAllocation.java | 78 + .../resource/link/MplsLabelResourceRequest.java | 37 + .../net/resource/link/package-info.java | 21 + .../org/onosproject/net/resource/package-info.java | 20 + .../org/onosproject/net/statistic/DefaultLoad.java | 111 ++ .../java/org/onosproject/net/statistic/Load.java | 51 + .../net/statistic/StatisticService.java | 85 + .../onosproject/net/statistic/StatisticStore.java | 65 + .../onosproject/net/statistic/package-info.java | 20 + .../org/onosproject/net/topology/ClusterId.java | 76 + .../net/topology/DefaultGraphDescription.java | 141 ++ .../net/topology/DefaultTopologyCluster.java | 97 ++ .../net/topology/DefaultTopologyEdge.java | 84 + .../net/topology/DefaultTopologyVertex.java | 66 + .../onosproject/net/topology/GraphDescription.java | 57 + .../org/onosproject/net/topology/LinkWeight.java | 25 + .../org/onosproject/net/topology/PathService.java | 51 + .../org/onosproject/net/topology/Topology.java | 71 + .../onosproject/net/topology/TopologyCluster.java | 51 + .../org/onosproject/net/topology/TopologyEdge.java | 33 + .../onosproject/net/topology/TopologyEvent.java | 78 + .../onosproject/net/topology/TopologyGraph.java | 25 + .../onosproject/net/topology/TopologyListener.java | 24 + .../onosproject/net/topology/TopologyProvider.java | 30 + .../net/topology/TopologyProviderRegistry.java | 25 + .../net/topology/TopologyProviderService.java | 37 + .../onosproject/net/topology/TopologyService.java | 135 ++ .../onosproject/net/topology/TopologyStore.java | 144 ++ .../net/topology/TopologyStoreDelegate.java | 24 + .../onosproject/net/topology/TopologyVertex.java | 33 + .../org/onosproject/net/topology/package-info.java | 20 + .../rest/AbstractApiDocRegistrator.java | 53 + .../rest/AbstractInjectionResource.java | 78 + .../org/onosproject/rest/AbstractWebResource.java | 98 ++ .../java/org/onosproject/rest/ApiDocProvider.java | 98 ++ .../java/org/onosproject/rest/ApiDocService.java | 58 + .../java/org/onosproject/rest/package-info.java | 20 + .../java/org/onosproject/security/AppGuard.java | 38 + .../org/onosproject/security/AppPermission.java | 110 ++ .../java/org/onosproject/security/Permission.java | 77 + .../onosproject/security/SecurityAdminService.java | 77 + .../org/onosproject/security/SecurityUtil.java | 82 + .../org/onosproject/security/package-info.java | 20 + .../java/org/onosproject/store/AbstractStore.java | 72 + .../src/main/java/org/onosproject/store/Store.java | 51 + .../java/org/onosproject/store/StoreDelegate.java | 33 + .../main/java/org/onosproject/store/Timestamp.java | 53 + .../messaging/ClusterCommunicationService.java | 166 ++ .../store/cluster/messaging/ClusterMessage.java | 160 ++ .../cluster/messaging/ClusterMessageHandler.java | 28 + .../store/cluster/messaging/Endpoint.java | 75 + .../store/cluster/messaging/MessageSubject.java | 68 + .../store/cluster/messaging/MessagingService.java | 75 + .../store/cluster/messaging/package-info.java | 20 + .../java/org/onosproject/store/package-info.java | 20 + .../store/service/AsyncAtomicCounter.java | 61 + .../store/service/AsyncConsistentMap.java | 283 ++++ .../onosproject/store/service/AtomicCounter.java | 59 + .../store/service/AtomicCounterBuilder.java | 75 + .../org/onosproject/store/service/AtomicValue.java | 69 + .../store/service/AtomicValueBuilder.java | 78 + .../store/service/AtomicValueEvent.java | 109 ++ .../store/service/AtomicValueEventListener.java | 28 + .../onosproject/store/service/ConsistentMap.java | 291 ++++ .../store/service/ConsistentMapBuilder.java | 143 ++ .../store/service/ConsistentMapException.java | 48 + .../onosproject/store/service/DatabaseUpdate.java | 220 +++ .../store/service/DistributedQueue.java | 62 + .../store/service/DistributedQueueBuilder.java | 79 + .../onosproject/store/service/DistributedSet.java | 41 + .../store/service/DistributedSetBuilder.java | 132 ++ .../store/service/EventuallyConsistentMap.java | 207 +++ .../service/EventuallyConsistentMapBuilder.java | 187 +++ .../service/EventuallyConsistentMapEvent.java | 124 ++ .../service/EventuallyConsistentMapListener.java | 29 + .../store/service/LogicalClockService.java | 35 + .../org/onosproject/store/service/MapEvent.java | 135 ++ .../store/service/MapEventListener.java | 28 + .../org/onosproject/store/service/MapInfo.java | 47 + .../store/service/MultiValuedTimestamp.java | 111 ++ .../onosproject/store/service/PartitionInfo.java | 81 + .../org/onosproject/store/service/Serializer.java | 81 + .../org/onosproject/store/service/SetEvent.java | 113 ++ .../store/service/SetEventListener.java | 28 + .../store/service/StorageAdminService.java | 75 + .../store/service/StorageException.java | 48 + .../onosproject/store/service/StorageService.java | 83 + .../org/onosproject/store/service/Transaction.java | 102 ++ .../store/service/TransactionContext.java | 78 + .../store/service/TransactionContextBuilder.java | 47 + .../store/service/TransactionException.java | 54 + .../store/service/TransactionalMap.java | 93 ++ .../org/onosproject/store/service/Versioned.java | 138 ++ .../store/service/WallClockTimestamp.java | 85 + .../onosproject/store/service/package-info.java | 21 + .../main/java/org/onosproject/ui/JsonUtils.java | 143 ++ .../java/org/onosproject/ui/RequestHandler.java | 142 ++ .../main/java/org/onosproject/ui/UiConnection.java | 42 + .../main/java/org/onosproject/ui/UiExtension.java | 200 +++ .../org/onosproject/ui/UiExtensionService.java | 53 + .../java/org/onosproject/ui/UiMessageHandler.java | 207 +++ .../onosproject/ui/UiMessageHandlerFactory.java | 33 + .../java/org/onosproject/ui/UiTopoOverlay.java | 122 ++ .../org/onosproject/ui/UiTopoOverlayFactory.java | 34 + .../src/main/java/org/onosproject/ui/UiView.java | 165 ++ .../main/java/org/onosproject/ui/UiViewHidden.java | 41 + .../main/java/org/onosproject/ui/package-info.java | 20 + .../org/onosproject/ui/table/CellComparator.java | 46 + .../org/onosproject/ui/table/CellFormatter.java | 34 + .../java/org/onosproject/ui/table/TableModel.java | 304 ++++ .../onosproject/ui/table/TableRequestHandler.java | 111 ++ .../java/org/onosproject/ui/table/TableUtils.java | 58 + .../ui/table/cell/AbstractCellComparator.java | 61 + .../ui/table/cell/AbstractCellFormatter.java | 42 + .../onosproject/ui/table/cell/AppIdFormatter.java | 41 + .../ui/table/cell/ConnectPointFormatter.java | 41 + .../ui/table/cell/DefaultCellComparator.java | 52 + .../ui/table/cell/DefaultCellFormatter.java | 39 + .../onosproject/ui/table/cell/EnumFormatter.java | 40 + .../onosproject/ui/table/cell/HexFormatter.java | 39 + .../ui/table/cell/HostLocationFormatter.java | 41 + .../onosproject/ui/table/cell/TimeFormatter.java | 72 + .../onosproject/ui/table/cell/package-info.java | 20 + .../org/onosproject/ui/table/package-info.java | 20 + .../org/onosproject/ui/topo/AbstractHighlight.java | 75 + .../java/org/onosproject/ui/topo/BaseLink.java | 43 + .../java/org/onosproject/ui/topo/BaseLinkMap.java | 31 + .../main/java/org/onosproject/ui/topo/BiLink.java | 104 ++ .../java/org/onosproject/ui/topo/BiLinkMap.java | 90 ++ .../java/org/onosproject/ui/topo/ButtonId.java | 70 + .../org/onosproject/ui/topo/DeviceHighlight.java | 33 + .../java/org/onosproject/ui/topo/Highlights.java | 190 +++ .../org/onosproject/ui/topo/HostHighlight.java | 33 + .../org/onosproject/ui/topo/LinkHighlight.java | 147 ++ .../src/main/java/org/onosproject/ui/topo/Mod.java | 66 + .../org/onosproject/ui/topo/NodeHighlight.java | 27 + .../org/onosproject/ui/topo/NodeSelection.java | 252 +++ .../org/onosproject/ui/topo/PropertyPanel.java | 353 +++++ .../org/onosproject/ui/topo/TopoConstants.java | 129 ++ .../org/onosproject/ui/topo/TopoElementType.java | 25 + .../java/org/onosproject/ui/topo/TopoJson.java | 160 ++ .../java/org/onosproject/ui/topo/TopoUtils.java | 159 ++ .../java/org/onosproject/ui/topo/package-info.java | 21 + .../onosproject/net/flow/doc-files/flow-design.png | Bin 0 -> 29150 bytes .../net/intent/doc-files/intent-design.png | Bin 0 -> 32496 bytes .../net/intent/doc-files/intent-states.png | Bin 0 -> 99143 bytes .../java/org/onosproject/TestApplicationId.java | 48 + .../src/test/java/org/onosproject/VersionTest.java | 83 + .../app/ApplicationAdminServiceAdapter.java | 78 + .../org/onosproject/app/ApplicationEventTest.java | 55 + .../onosproject/app/ApplicationExceptionTest.java | 36 + .../onosproject/app/ApplicationServiceAdapter.java | 60 + .../onosproject/app/ApplicationStoreAdapter.java | 78 + .../app/DefaultApplicationDescriptionTest.java | 66 + .../onosproject/cfg/ComponentConfigAdapter.java | 53 + .../org/onosproject/cfg/ConfigPropertyTest.java | 97 ++ .../onosproject/cluster/ClusterServiceAdapter.java | 64 + .../cluster/ControllerNodeToNodeIdTest.java | 59 + .../onosproject/cluster/LeadershipEventTest.java | 76 + .../cluster/LeadershipServiceAdapter.java | 87 + .../org/onosproject/cluster/LeadershipTest.java | 75 + .../java/org/onosproject/cluster/RoleInfoTest.java | 60 + .../java/org/onosproject/codec/JsonCodecTest.java | 99 ++ .../core/ApplicationIdStoreAdapter.java | 43 + .../org/onosproject/core/CoreServiceAdapter.java | 54 + .../onosproject/core/DefaultApplicationTest.java | 63 + .../org/onosproject/core/DefaultGroupIdTest.java | 41 + .../core/UnavailableIdExceptionTest.java | 36 + .../org/onosproject/event/AbstractEventTest.java | 79 + .../java/org/onosproject/event/BrokenListener.java | 28 + .../event/DefaultEventSinkRegistryTest.java | 71 + .../event/EventDeliveryServiceAdapter.java | 60 + .../onosproject/event/ListenerRegistryTest.java | 74 + .../test/java/org/onosproject/event/TestEvent.java | 34 + .../java/org/onosproject/event/TestListener.java | 34 + .../onosproject/event/TestListenerRegistry.java | 36 + .../mastership/MastershipServiceAdapter.java | 67 + .../onosproject/mastership/MastershipTermTest.java | 57 + .../java/org/onosproject/net/ConnectPointTest.java | 110 ++ .../onosproject/net/DefaultAnnotationsTest.java | 100 ++ .../org/onosproject/net/DefaultDeviceTest.java | 79 + .../org/onosproject/net/DefaultEdgeLinkTest.java | 90 ++ .../java/org/onosproject/net/DefaultHostTest.java | 51 + .../java/org/onosproject/net/DefaultLinkTest.java | 65 + .../java/org/onosproject/net/DefaultPortTest.java | 70 + .../java/org/onosproject/net/DeviceIdTest.java | 37 + .../test/java/org/onosproject/net/HostIdTest.java | 44 + .../org/onosproject/net/IndexedLambdaTest.java | 35 + .../test/java/org/onosproject/net/LinkKeyTest.java | 129 ++ .../java/org/onosproject/net/NetTestTools.java | 138 ++ .../java/org/onosproject/net/OchSignalTest.java | 40 + .../java/org/onosproject/net/PortNumberTest.java | 43 + .../java/org/onosproject/net/TestDeviceParams.java | 55 + .../net/config/NetworkConfigRegistryAdapter.java | 42 + .../net/config/NetworkConfigServiceAdapter.java | 90 ++ .../net/device/DefaultDeviceDescriptionTest.java | 54 + .../net/device/DefaultPortStatisticsTest.java | 126 ++ .../net/device/DeviceClockServiceAdapter.java | 21 + .../onosproject/net/device/DeviceEventTest.java | 63 + .../net/device/DeviceServiceAdapter.java | 110 ++ .../net/driver/DefaultDriverDataTest.java | 78 + .../net/driver/DefaultDriverHandlerTest.java | 55 + .../net/driver/DefaultDriverProviderTest.java | 49 + .../onosproject/net/driver/DefaultDriverTest.java | 89 ++ .../org/onosproject/net/driver/TestBehaviour.java | 22 + .../onosproject/net/driver/TestBehaviourImpl.java | 22 + .../net/driver/TestBehaviourNoConstructorImpl.java | 26 + .../onosproject/net/driver/TestBehaviourTwo.java | 22 + .../net/driver/TestBehaviourTwoImpl.java | 22 + .../net/driver/XmlDriverLoaderTest.java | 80 + .../onosproject/net/flow/BatchOperationTest.java | 153 ++ .../onosproject/net/flow/DefaultFlowEntryTest.java | 161 ++ .../onosproject/net/flow/DefaultFlowRuleTest.java | 161 ++ .../net/flow/DefaultTrafficSelectorTest.java | 295 ++++ .../net/flow/DefaultTrafficTreatmentTest.java | 124 ++ .../java/org/onosproject/net/flow/FlowIdTest.java | 65 + .../net/flow/FlowRuleBatchOperationTest.java | 60 + .../net/flow/FlowRuleBatchRequestTest.java | 63 + .../onosproject/net/flow/FlowRuleEventTest.java | 77 + .../net/flow/FlowRuleExtPayLoadTest.java | 36 + .../net/flow/FlowRuleServiceAdapter.java | 75 + .../net/flow/criteria/CriteriaTest.java | 1138 +++++++++++++ .../net/flow/instructions/InstructionsTest.java | 725 +++++++++ .../net/flowobjective/ObjectiveTest.java | 313 ++++ .../net/group/DefaultGroupDescriptionTest.java | 96 ++ .../onosproject/net/group/DefaultGroupTest.java | 97 ++ .../org/onosproject/net/group/GroupBucketTest.java | 133 ++ .../onosproject/net/group/GroupOperationTest.java | 89 ++ .../net/host/DefaultHostDecriptionTest.java | 57 + .../org/onosproject/net/host/HostEventTest.java | 72 + .../onosproject/net/host/HostServiceAdapter.java | 102 ++ .../net/host/InterfaceIpAddressTest.java | 246 +++ .../onosproject/net/host/PortAddressesTest.java | 113 ++ .../onosproject/net/intent/AbstractIntentTest.java | 35 + .../net/intent/ConnectivityIntentTest.java | 47 + .../onosproject/net/intent/FakeIntentManager.java | 268 ++++ .../net/intent/HostToHostIntentTest.java | 126 ++ .../org/onosproject/net/intent/IntentDataTest.java | 179 +++ .../net/intent/IntentExceptionTest.java | 48 + .../org/onosproject/net/intent/IntentIdTest.java | 95 ++ .../net/intent/IntentServiceAdapter.java | 89 ++ .../onosproject/net/intent/IntentServiceTest.java | 252 +++ .../org/onosproject/net/intent/IntentTest.java | 52 + .../onosproject/net/intent/IntentTestsMocks.java | 496 ++++++ .../java/org/onosproject/net/intent/KeyTest.java | 121 ++ .../net/intent/LinkCollectionIntentTest.java | 209 +++ .../onosproject/net/intent/MockIdGenerator.java | 32 + .../org/onosproject/net/intent/MplsIntentTest.java | 117 ++ .../onosproject/net/intent/MplsPathIntentTest.java | 110 ++ .../intent/MultiPointToSinglePointIntentTest.java | 66 + .../net/intent/OpticalConnectivityIntentTest.java | 35 + .../net/intent/OpticalPathIntentTest.java | 97 ++ .../net/intent/PartitionServiceAdapter.java | 45 + .../org/onosproject/net/intent/PathIntentTest.java | 115 ++ .../net/intent/PointToPointIntentTest.java | 66 + .../intent/SinglePointToMultiPointIntentTest.java | 66 + .../net/intent/TestInstallableIntent.java | 53 + .../org/onosproject/net/intent/TestIntent.java | 47 + .../net/intent/TestSubclassInstallableIntent.java | 37 + .../onosproject/net/intent/TestSubclassIntent.java | 37 + .../java/org/onosproject/net/intent/TestTools.java | 141 ++ .../net/intent/TestableIntentService.java | 27 + .../net/intent/TwoWayP2PIntentTest.java | 100 ++ .../constraint/AnnotationConstraintTest.java | 97 ++ .../intent/constraint/ConstraintObjectsTest.java | 135 ++ .../intent/constraint/LatencyConstraintTest.java | 124 ++ .../intent/constraint/ObstacleConstraintTest.java | 102 ++ .../intent/constraint/WaypointConstraintTest.java | 104 ++ .../net/link/DefaultLinkDescriptionTest.java | 45 + .../org/onosproject/net/link/LinkEventTest.java | 56 + .../onosproject/net/link/LinkServiceAdapter.java | 97 ++ .../onosproject/net/meter/DefaultMeterTest.java | 99 ++ .../onosproject/net/meter/MeterOperationTest.java | 128 ++ .../net/newresource/ResourceAllocationTest.java | 50 + .../net/newresource/ResourcePathTest.java | 82 + .../net/packet/DefaultInboundPacketTest.java | 81 + .../net/packet/DefaultOutboundPacketTest.java | 82 + .../net/packet/DefaultPacketContextTest.java | 112 ++ .../net/packet/PacketServiceAdapter.java | 44 + .../net/provider/AbstractProviderRegistryTest.java | 108 ++ .../net/provider/AbstractProviderTest.java | 33 + .../onosproject/net/provider/ProviderIdTest.java | 35 + .../org/onosproject/net/provider/TestProvider.java | 32 + .../onosproject/net/resource/MplsObjectsTest.java | 89 ++ .../onosproject/net/statistic/DefaultLoadTest.java | 92 ++ .../net/statistic/StatisticServiceAdapter.java | 61 + .../onosproject/net/topology/ClusterIdTest.java | 41 + .../net/topology/DefaultGraphDescriptionTest.java | 60 + .../net/topology/DefaultTopologyClusterTest.java | 54 + .../net/topology/DefaultTopologyEdgeTest.java | 70 + .../net/topology/DefaultTopologyVertexTest.java | 44 + .../net/topology/TopologyServiceAdapter.java | 92 ++ .../ClusterCommunicationServiceAdapter.java | 88 ++ .../cluster/messaging/ClusterMessageTest.java | 82 + .../store/cluster/messaging/EndpointTest.java | 68 + .../cluster/messaging/MessageSubjectTest.java | 64 + .../store/service/AtomicValueEventTest.java | 71 + .../store/service/ConsistentMapAdapter.java | 149 ++ .../store/service/DatabaseUpdateTest.java | 127 ++ .../service/EventuallyConsistentMapAdapter.java | 111 ++ .../service/EventuallyConsistentMapEventTest.java | 82 + .../onosproject/store/service/MapEventTest.java | 61 + .../store/service/MultiValuedTimestampTest.java | 94 ++ .../onosproject/store/service/SetEventTest.java | 75 + .../store/service/StorageServiceAdapter.java | 56 + .../store/service/TestAtomicCounter.java | 85 + .../store/service/TestConsistentMap.java | 287 ++++ .../store/service/TestEventuallyConsistentMap.java | 238 +++ .../store/service/TestStorageService.java | 55 + .../onosproject/store/service/VersionedTest.java | 84 + .../store/service/WallClockTimestampTest.java | 66 + .../onosproject/ui/UiExtensionServiceAdapter.java | 41 + .../java/org/onosproject/ui/UiExtensionTest.java | 140 ++ .../org/onosproject/ui/table/TableModelTest.java | 338 ++++ .../org/onosproject/ui/table/TableUtilsTest.java | 45 + .../ui/table/cell/AbstractCellComparatorTest.java | 59 + .../ui/table/cell/AbstractCellFormatterTest.java | 52 + .../ui/table/cell/AppIdFormatterTest.java | 50 + .../ui/table/cell/ConnectPointFormatterTest.java | 45 + .../ui/table/cell/DefaultCellComparatorTest.java | 147 ++ .../ui/table/cell/DefaultCellFormatterTest.java | 71 + .../ui/table/cell/EnumFormatterTest.java | 60 + .../ui/table/cell/HexFormatterTest.java | 57 + .../ui/table/cell/HostLocationFormatterTest.java | 46 + .../ui/table/cell/TimeFormatterTest.java | 52 + .../org/onosproject/ui/topo/BiLinkMapTest.java | 76 + .../java/org/onosproject/ui/topo/BiLinkTest.java | 62 + .../org/onosproject/ui/topo/BiLinkTestBase.java | 98 ++ .../java/org/onosproject/ui/topo/ButtonIdTest.java | 56 + .../org/onosproject/ui/topo/HighlightsTest.java | 91 ++ .../org/onosproject/ui/topo/LinkHighlightTest.java | 116 ++ .../test/java/org/onosproject/ui/topo/ModTest.java | 62 + .../org/onosproject/ui/topo/NodeSelectionTest.java | 349 ++++ .../org/onosproject/ui/topo/PropertyPanelTest.java | 238 +++ .../java/org/onosproject/ui/topo/TopoJsonTest.java | 72 + .../src/onos/core/api/src/test/resources/css.html | 2 + .../core/api/src/test/resources/custom/css.html | 1 + .../core/api/src/test/resources/custom/js.html | 1 + .../src/onos/core/api/src/test/resources/js.html | 2 + .../org/onosproject/net/driver/drivers.1.xml | 33 + .../org/onosproject/net/driver/drivers.bad.xml | 22 + .../org/onosproject/net/driver/drivers.noclass.xml | 22 + .../net/driver/drivers.noconstructor.xml | 22 + framework/src/onos/core/common/pom.xml | 58 + .../org/onosproject/codec/impl/AnnotatedCodec.java | 64 + .../onosproject/codec/impl/AnnotationsCodec.java | 49 + .../onosproject/codec/impl/ApplicationCodec.java | 49 + .../org/onosproject/codec/impl/CodecManager.java | 132 ++ .../onosproject/codec/impl/ConnectPointCodec.java | 74 + .../codec/impl/ConnectivityIntentCodec.java | 118 ++ .../onosproject/codec/impl/ConstraintCodec.java | 63 + .../codec/impl/ControllerNodeCodec.java | 57 + .../org/onosproject/codec/impl/CriterionCodec.java | 78 + .../codec/impl/DecodeConstraintCodecHelper.java | 225 +++ .../codec/impl/DecodeCriterionCodecHelper.java | 449 ++++++ .../codec/impl/DecodeInstructionCodecHelper.java | 235 +++ .../org/onosproject/codec/impl/DeviceCodec.java | 93 ++ .../org/onosproject/codec/impl/DriverCodec.java | 78 + .../codec/impl/EncodeConstraintCodecHelper.java | 201 +++ .../codec/impl/EncodeCriterionCodecHelper.java | 396 +++++ .../codec/impl/EncodeInstructionCodecHelper.java | 243 +++ .../org/onosproject/codec/impl/EthernetCodec.java | 58 + .../org/onosproject/codec/impl/FlowEntryCodec.java | 70 + .../org/onosproject/codec/impl/FlowRuleCodec.java | 94 ++ .../onosproject/codec/impl/GroupBucketCodec.java | 64 + .../org/onosproject/codec/impl/GroupCodec.java | 79 + .../java/org/onosproject/codec/impl/HostCodec.java | 55 + .../onosproject/codec/impl/HostLocationCodec.java | 39 + .../codec/impl/HostToHostIntentCodec.java | 70 + .../onosproject/codec/impl/InstructionCodec.java | 73 + .../org/onosproject/codec/impl/IntentCodec.java | 112 ++ .../java/org/onosproject/codec/impl/LinkCodec.java | 80 + .../java/org/onosproject/codec/impl/LoadCodec.java | 45 + .../java/org/onosproject/codec/impl/PathCodec.java | 47 + .../codec/impl/PointToPointIntentCodec.java | 80 + .../java/org/onosproject/codec/impl/PortCodec.java | 160 ++ .../codec/impl/TopologyClusterCodec.java | 41 + .../org/onosproject/codec/impl/TopologyCodec.java | 41 + .../codec/impl/TrafficSelectorCodec.java | 71 + .../codec/impl/TrafficTreatmentCodec.java | 76 + .../org/onosproject/codec/impl/package-info.java | 20 + .../org/onosproject/common/DefaultTopology.java | 502 ++++++ .../onosproject/common/DefaultTopologyGraph.java | 43 + .../onosproject/common/app/ApplicationArchive.java | 432 +++++ .../org/onosproject/common/app/package-info.java | 20 + .../java/org/onosproject/common/package-info.java | 21 + .../codec/impl/ConnectPointJsonMatcher.java | 71 + .../codec/impl/ConstraintCodecTest.java | 202 +++ .../onosproject/codec/impl/CriterionCodecTest.java | 445 ++++++ .../codec/impl/CriterionJsonMatcher.java | 609 +++++++ .../onosproject/codec/impl/DeviceCodecTest.java | 59 + .../onosproject/codec/impl/DriverCodecTest.java | 65 + .../onosproject/codec/impl/DriverJsonMatcher.java | 118 ++ .../onosproject/codec/impl/EthernetCodecTest.java | 55 + .../codec/impl/EthernetJsonMatcher.java | 122 ++ .../onosproject/codec/impl/FlowRuleCodecTest.java | 546 +++++++ .../codec/impl/GroupBucketJsonMatcher.java | 87 + .../org/onosproject/codec/impl/GroupCodecTest.java | 61 + .../onosproject/codec/impl/GroupJsonMatcher.java | 120 ++ .../codec/impl/ImmutableCodecsTest.java | 65 + .../codec/impl/InstructionCodecTest.java | 247 +++ .../codec/impl/InstructionJsonMatcher.java | 438 +++++ .../onosproject/codec/impl/IntentCodecTest.java | 288 ++++ .../onosproject/codec/impl/IntentJsonMatcher.java | 512 ++++++ .../org/onosproject/codec/impl/JsonCodecUtils.java | 83 + .../org/onosproject/codec/impl/LinkCodecTest.java | 54 + .../org/onosproject/codec/impl/LoadCodecTest.java | 47 + .../onosproject/codec/impl/MockCodecContext.java | 64 + .../org/onosproject/codec/impl/PortCodecTest.java | 66 + .../onosproject/common/DefaultTopologyTest.java | 141 ++ .../common/app/ApplicationArchiveTest.java | 157 ++ .../common/event/impl/TestEventDispatcher.java | 48 + .../org/onosproject/store/trivial/PathKey.java | 55 + .../store/trivial/SimpleApplicationIdStore.java | 70 + .../store/trivial/SimpleApplicationStore.java | 170 ++ .../store/trivial/SimpleApplicationStoreTest.java | 154 ++ .../store/trivial/SimpleClusterStore.java | 139 ++ .../store/trivial/SimpleComponentConfigStore.java | 62 + .../store/trivial/SimpleDeviceStore.java | 691 ++++++++ .../store/trivial/SimpleDeviceStoreTest.java | 530 +++++++ .../store/trivial/SimpleFlowRuleStore.java | 327 ++++ .../store/trivial/SimpleGroupStore.java | 717 +++++++++ .../store/trivial/SimpleGroupStoreTest.java | 482 ++++++ .../onosproject/store/trivial/SimpleHostStore.java | 293 ++++ .../store/trivial/SimpleIdBlockStore.java | 48 + .../store/trivial/SimpleIntentStore.java | 212 +++ .../store/trivial/SimpleLeadershipManager.java | 135 ++ .../store/trivial/SimpleLinkResourceStore.java | 286 ++++ .../store/trivial/SimpleLinkResourceStoreTest.java | 307 ++++ .../onosproject/store/trivial/SimpleLinkStore.java | 366 +++++ .../store/trivial/SimpleLinkStoreTest.java | 542 +++++++ .../store/trivial/SimpleMastershipStore.java | 388 +++++ .../store/trivial/SimpleMastershipStoreTest.java | 184 +++ .../store/trivial/SimplePacketStore.java | 64 + .../store/trivial/SimpleStatisticStore.java | 211 +++ .../store/trivial/SimpleTopologyStore.java | 157 ++ .../store/trivial/SystemClockTimestamp.java | 83 + .../onosproject/store/trivial/package-info.java | 21 + .../codec/impl/AnnotationConstraint.json | 5 + .../codec/impl/AsymmetricPathConstraint.json | 3 + .../codec/impl/BandwidthConstraint.json | 4 + .../onosproject/codec/impl/HostToHostIntent.json | 19 + .../onosproject/codec/impl/LambdaConstraint.json | 4 + .../onosproject/codec/impl/LatencyConstraint.json | 4 + .../onosproject/codec/impl/LinkTypeConstraint.json | 5 + .../onosproject/codec/impl/ObstacleConstraint.json | 4 + .../onosproject/codec/impl/PointToPointIntent.json | 38 + .../onosproject/codec/impl/WaypointConstraint.json | 4 + .../org/onosproject/codec/impl/criteria-flow.json | 44 + .../onosproject/codec/impl/instructions-flow.json | 39 + .../org/onosproject/codec/impl/sigid-flow.json | 20 + .../org/onosproject/codec/impl/simple-flow.json | 12 + .../resources/org/onosproject/common/app/app.xml | 29 + .../resources/org/onosproject/common/app/app.zip | Bin 0 -> 1450 bytes framework/src/onos/core/net/pom.xml | 98 ++ .../onosproject/app/impl/ApplicationManager.java | 250 +++ .../org/onosproject/app/impl/package-info.java | 20 + .../cfg/impl/ComponentConfigManager.java | 281 ++++ .../cfg/impl/ConfigPropertyDefinitions.java | 81 + .../org/onosproject/cfg/impl/package-info.java | 20 + .../onosproject/cluster/impl/ClusterManager.java | 156 ++ .../cluster/impl/MastershipManager.java | 282 ++++ .../org/onosproject/cluster/impl/package-info.java | 20 + .../core/impl/BlockAllocatorBasedIdGenerator.java | 65 + .../org/onosproject/core/impl/CoreManager.java | 190 +++ .../onosproject/core/impl/IdBlockAllocator.java | 38 + .../core/impl/MetricsManagerComponent.java | 41 + .../core/impl/StoreBasedIdBlockAllocator.java | 46 + .../org/onosproject/core/impl/package-info.java | 20 + .../event/impl/CoreEventDispatcher.java | 175 ++ .../org/onosproject/event/impl/package-info.java | 20 + .../net/config/impl/BasicNetworkConfigs.java | 115 ++ .../net/config/impl/NetworkConfigLoader.java | 218 +++ .../net/config/impl/NetworkConfigManager.java | 288 ++++ .../onosproject/net/config/impl/package-info.java | 20 + .../net/device/impl/BasicDeviceOperator.java | 107 ++ .../onosproject/net/device/impl/DeviceManager.java | 765 +++++++++ .../net/device/impl/OpticalPortOperator.java | 173 ++ .../onosproject/net/device/impl/package-info.java | 20 + .../onosproject/net/driver/impl/DriverManager.java | 188 +++ .../onosproject/net/driver/impl/package-info.java | 20 + .../net/edgeservice/impl/EdgeManager.java | 241 +++ .../net/edgeservice/impl/package-info.java | 4 + .../onosproject/net/flow/impl/FlowRuleManager.java | 593 +++++++ .../onosproject/net/flow/impl/package-info.java | 20 + .../flowobjective/impl/FlowObjectiveManager.java | 416 +++++ .../impl/composition/FilterTable.java | 61 + .../FlowObjectiveCompositionManager.java | 439 +++++ .../composition/FlowObjectiveCompositionTree.java | 271 ++++ .../composition/FlowObjectiveCompositionUtil.java | 488 ++++++ .../impl/composition/ForwardTable.java | 109 ++ .../impl/composition/ForwardUpdateTable.java | 46 + .../flowobjective/impl/composition/NextTable.java | 61 + .../impl/composition/package-info.java | 20 + .../net/flowobjective/impl/package-info.java | 20 + .../onosproject/net/group/impl/GroupManager.java | 318 ++++ .../onosproject/net/group/impl/package-info.java | 20 + .../net/host/impl/BasicHostOperator.java | 84 + .../org/onosproject/net/host/impl/HostManager.java | 300 ++++ .../org/onosproject/net/host/impl/HostMonitor.java | 288 ++++ .../onosproject/net/host/impl/package-info.java | 20 + .../net/intent/impl/CompilerRegistry.java | 128 ++ .../net/intent/impl/IntentAccumulator.java | 82 + .../onosproject/net/intent/impl/IntentCleanup.java | 254 +++ .../intent/impl/IntentCompilationException.java | 37 + .../intent/impl/IntentInstallationException.java | 37 + .../onosproject/net/intent/impl/IntentManager.java | 488 ++++++ .../net/intent/impl/IntentProcessor.java | 46 + .../net/intent/impl/IntentRemovalException.java | 37 + .../net/intent/impl/ObjectiveTracker.java | 457 ++++++ .../net/intent/impl/ObjectiveTrackerService.java | 69 + .../net/intent/impl/PathNotFoundException.java | 46 + .../net/intent/impl/TopologyChangeDelegate.java | 37 + .../impl/compiler/ConnectivityIntentCompiler.java | 152 ++ .../impl/compiler/HostToHostIntentCompiler.java | 110 ++ .../compiler/LinkCollectionIntentCompiler.java | 138 ++ .../intent/impl/compiler/MplsIntentCompiler.java | 91 ++ .../impl/compiler/MplsPathIntentCompiler.java | 291 ++++ .../MultiPointToSinglePointIntentCompiler.java | 151 ++ .../compiler/OpticalCircuitIntentCompiler.java | 372 +++++ .../OpticalConnectivityIntentCompiler.java | 305 ++++ .../impl/compiler/OpticalPathIntentCompiler.java | 195 +++ .../intent/impl/compiler/PathIntentCompiler.java | 116 ++ .../impl/compiler/PointToPointIntentCompiler.java | 104 ++ .../SinglePointToMultiPointIntentCompiler.java | 85 + .../impl/compiler/TwoWayP2PIntentCompiler.java | 72 + .../net/intent/impl/compiler/package-info.java | 20 + .../onosproject/net/intent/impl/package-info.java | 21 + .../net/intent/impl/phase/Compiling.java | 73 + .../onosproject/net/intent/impl/phase/Corrupt.java | 44 + .../onosproject/net/intent/impl/phase/Failed.java | 44 + .../intent/impl/phase/FinalIntentProcessPhase.java | 44 + .../net/intent/impl/phase/InstallRequest.java | 55 + .../net/intent/impl/phase/Installing.java | 58 + .../net/intent/impl/phase/IntentProcessPhase.java | 73 + .../net/intent/impl/phase/IntentWorker.java | 52 + .../net/intent/impl/phase/PurgeRequest.java | 70 + .../net/intent/impl/phase/WithdrawRequest.java | 70 + .../net/intent/impl/phase/Withdrawing.java | 55 + .../net/intent/impl/phase/Withdrawn.java | 44 + .../net/intent/impl/phase/package-info.java | 20 + .../net/link/impl/BasicLinkOperator.java | 86 + .../org/onosproject/net/link/impl/LinkManager.java | 343 ++++ .../onosproject/net/link/impl/package-info.java | 20 + .../newresource/impl/ResourceDeviceListener.java | 86 + .../net/newresource/impl/ResourceLinkListener.java | 152 ++ .../net/newresource/impl/ResourceManager.java | 148 ++ .../net/newresource/impl/ResourceRegistrar.java | 73 + .../net/newresource/impl/package-info.java | 20 + .../onosproject/net/packet/impl/PacketManager.java | 329 ++++ .../onosproject/net/packet/impl/package-info.java | 22 + .../net/proxyarp/impl/ProxyArpManager.java | 447 ++++++ .../net/proxyarp/impl/package-info.java | 20 + .../net/resource/impl/DeviceResourceManager.java | 104 ++ .../net/resource/impl/LinkResourceManager.java | 293 ++++ .../net/resource/impl/package-info.java | 20 + .../net/statistic/impl/StatisticManager.java | 379 +++++ .../net/statistic/impl/package-info.java | 20 + .../net/topology/impl/DefaultTopologyProvider.java | 287 ++++ .../onosproject/net/topology/impl/PathManager.java | 190 +++ .../net/topology/impl/TopologyManager.java | 215 +++ .../net/topology/impl/package-info.java | 20 + .../app/impl/ApplicationManagerTest.java | 198 +++ .../app/impl/FeaturesServiceAdapter.java | 168 ++ .../cfg/impl/ConfigPropertyDefinitionsTest.java | 49 + .../cluster/impl/MastershipManagerTest.java | 180 +++ .../core/impl/DummyIdBlockAllocator.java | 48 + .../impl/IdBlockAllocatorBasedIdGeneratorTest.java | 58 + .../org/onosproject/core/impl/TestCoreManager.java | 29 + .../event/impl/CoreEventDispatcherTest.java | 132 ++ .../net/config/impl/NetworkConfigManagerTest.java | 242 +++ .../net/device/impl/BasicDeviceOperatorTest.java | 89 ++ .../net/device/impl/DeviceManagerTest.java | 331 ++++ .../net/device/impl/OpticalPortOperatorTest.java | 80 + .../net/edgeservice/impl/EdgeManagerTest.java | 514 ++++++ .../net/flow/impl/FlowRuleManagerTest.java | 640 ++++++++ .../impl/FlowObjectiveCompositionTreeTest.java | 603 +++++++ .../net/group/impl/GroupManagerTest.java | 536 +++++++ .../net/host/impl/BasicHostOperatorTest.java | 76 + .../onosproject/net/host/impl/HostManagerTest.java | 529 +++++++ .../onosproject/net/host/impl/HostMonitorTest.java | 320 ++++ ...sHaveEntryWithSourceDestinationPairMatcher.java | 97 ++ .../net/intent/impl/IntentAccumulatorTest.java | 160 ++ .../net/intent/impl/IntentCleanupTest.java | 261 +++ .../net/intent/impl/IntentCleanupTestMock.java | 285 ++++ .../net/intent/impl/IntentManagerTest.java | 672 ++++++++ .../net/intent/impl/MockFlowRuleService.java | 116 ++ .../net/intent/impl/ObjectiveTrackerTest.java | 326 ++++ .../compiler/HostToHostIntentCompilerTest.java | 167 ++ .../compiler/LinkCollectionIntentCompilerTest.java | 163 ++ .../impl/compiler/MplsIntentCompilerTest.java | 188 +++ .../impl/compiler/MplsPathIntentCompilerTest.java | 142 ++ .../MultiPointToSinglePointIntentCompilerTest.java | 276 ++++ .../compiler/OpticalPathIntentCompilerTest.java | 147 ++ .../impl/compiler/PathIntentCompilerTest.java | 172 ++ .../compiler/PointToPointIntentCompilerTest.java | 320 ++++ .../net/intent/impl/phase/CompilingTest.java | 149 ++ .../net/link/impl/BasicLinkOperatorTest.java | 77 + .../onosproject/net/link/impl/LinkManagerTest.java | 311 ++++ .../net/proxyarp/impl/ProxyArpManagerTest.java | 667 ++++++++ .../topology/impl/DefaultTopologyProviderTest.java | 194 +++ .../net/topology/impl/PathManagerTest.java | 164 ++ .../net/topology/impl/TopologyManagerTest.java | 215 +++ framework/src/onos/core/pom.xml | 85 + framework/src/onos/core/security/pom.xml | 65 + .../security/impl/DefaultPolicyBuilder.java | 433 +++++ .../security/impl/SecurityModeManager.java | 289 ++++ .../onosproject/security/impl/package-info.java | 20 + .../store/DistributedSecurityModeStore.java | 315 ++++ .../onosproject/security/store/SecurityInfo.java | 41 + .../security/store/SecurityModeEvent.java | 48 + .../security/store/SecurityModeListener.java | 25 + .../security/store/SecurityModeState.java | 43 + .../security/store/SecurityModeStore.java | 104 ++ .../security/store/SecurityModeStoreDelegate.java | 25 + framework/src/onos/core/store/dist/pom.xml | 114 ++ .../store/app/GossipApplicationStore.java | 429 +++++ .../org/onosproject/store/app/package-info.java | 20 + .../store/cfg/GossipComponentConfigStore.java | 120 ++ .../org/onosproject/store/cfg/package-info.java | 20 + .../store/cluster/impl/ClusterDefinition.java | 58 + .../cluster/impl/ClusterDefinitionManager.java | 179 +++ .../store/cluster/impl/ClusterDefinitionStore.java | 63 + .../impl/ClusterManagementMessageSubjects.java | 26 + .../store/cluster/impl/ClusterMembershipEvent.java | 41 + .../cluster/impl/ClusterMembershipEventType.java | 24 + .../store/cluster/impl/ClusterNodesDelegate.java | 54 + .../cluster/impl/DistributedClusterStore.java | 280 ++++ .../onosproject/store/cluster/impl/NodeInfo.java | 118 ++ .../cluster/impl/PhiAccrualFailureDetector.java | 119 ++ .../store/cluster/impl/package-info.java | 20 + .../impl/ClusterCommunicationManager.java | 261 +++ .../messaging/impl/IOLoopMessagingManager.java | 40 + .../messaging/impl/NettyMessagingManager.java | 72 + .../store/cluster/messaging/impl/package-info.java | 20 + .../config/impl/DistributedNetworkConfigStore.java | 289 ++++ .../store/config/impl/package-info.java | 20 + .../consistent/impl/AsyncCachingConsistentMap.java | 71 + .../store/consistent/impl/CommitResponse.java | 61 + .../impl/ConsistentMapBackedJavaMap.java | 145 ++ .../impl/CopycatCommunicationProtocol.java | 134 ++ .../store/consistent/impl/Database.java | 106 ++ .../store/consistent/impl/DatabaseConfig.java | 157 ++ .../store/consistent/impl/DatabaseDefinition.java | 108 ++ .../consistent/impl/DatabaseDefinitionStore.java | 74 + .../store/consistent/impl/DatabaseManager.java | 455 ++++++ .../store/consistent/impl/DatabasePartitioner.java | 45 + .../store/consistent/impl/DatabaseProxy.java | 224 +++ .../store/consistent/impl/DatabaseSerializer.java | 103 ++ .../store/consistent/impl/DatabaseState.java | 114 ++ .../consistent/impl/DefaultAsyncAtomicCounter.java | 84 + .../consistent/impl/DefaultAsyncConsistentMap.java | 465 ++++++ .../consistent/impl/DefaultAtomicCounter.java | 82 + .../impl/DefaultAtomicCounterBuilder.java | 77 + .../store/consistent/impl/DefaultAtomicValue.java | 138 ++ .../consistent/impl/DefaultAtomicValueBuilder.java | 71 + .../consistent/impl/DefaultConsistentMap.java | 204 +++ .../impl/DefaultConsistentMapBuilder.java | 141 ++ .../store/consistent/impl/DefaultDatabase.java | 243 +++ .../consistent/impl/DefaultDatabaseState.java | 368 +++++ .../consistent/impl/DefaultDistributedQueue.java | 129 ++ .../impl/DefaultDistributedQueueBuilder.java | 81 + .../consistent/impl/DefaultDistributedSet.java | 234 +++ .../impl/DefaultDistributedSetBuilder.java | 93 ++ .../store/consistent/impl/DefaultTransaction.java | 70 + .../consistent/impl/DefaultTransactionContext.java | 116 ++ .../impl/DefaultTransactionContextBuilder.java | 50 + .../consistent/impl/DefaultTransactionalMap.java | 204 +++ .../impl/DistributedLeadershipManager.java | 605 +++++++ .../onosproject/store/consistent/impl/Match.java | 129 ++ .../store/consistent/impl/MeteringAgent.java | 134 ++ .../store/consistent/impl/PartitionedDatabase.java | 386 +++++ .../store/consistent/impl/Partitioner.java | 33 + .../onosproject/store/consistent/impl/Result.java | 121 ++ .../consistent/impl/SimpleKeyHashPartitioner.java | 38 + .../impl/SimpleTableHashPartitioner.java | 39 + .../store/consistent/impl/StateMachineUpdate.java | 91 ++ .../store/consistent/impl/TransactionManager.java | 126 ++ .../store/consistent/impl/UpdateResult.java | 85 + .../store/consistent/impl/package-info.java | 21 + .../onosproject/store/core/impl/AppIdEvent.java | 34 + .../store/core/impl/AppIdStoreDelegate.java | 24 + .../core/impl/ConsistentApplicationIdStore.java | 154 ++ .../store/core/impl/ConsistentIdBlockStore.java | 64 + .../store/core/impl/LogicalClockManager.java | 51 + .../onosproject/store/core/impl/package-info.java | 20 + .../impl/DeviceAntiEntropyAdvertisement.java | 72 + .../device/impl/DeviceAntiEntropyRequest.java | 61 + .../store/device/impl/DeviceClockManager.java | 82 + .../store/device/impl/DeviceDescriptions.java | 134 ++ .../store/device/impl/DeviceFragmentId.java | 69 + .../store/device/impl/DeviceInjectedEvent.java | 49 + .../onosproject/store/device/impl/DeviceKey.java | 70 + .../store/device/impl/ECDeviceStore.java | 784 +++++++++ .../store/device/impl/GossipDeviceStore.java | 1670 ++++++++++++++++++++ .../impl/GossipDeviceStoreMessageSubjects.java | 41 + .../store/device/impl/InternalDeviceEvent.java | 71 + .../device/impl/InternalDeviceEventSerializer.java | 60 + .../device/impl/InternalDeviceOfflineEvent.java | 64 + .../impl/InternalDeviceOfflineEventSerializer.java | 53 + .../device/impl/InternalDeviceRemovedEvent.java | 64 + .../store/device/impl/InternalPortEvent.java | 73 + .../device/impl/InternalPortEventSerializer.java | 62 + .../store/device/impl/InternalPortStatusEvent.java | 71 + .../impl/InternalPortStatusEventSerializer.java | 58 + .../store/device/impl/PortFragmentId.java | 76 + .../store/device/impl/PortInjectedEvent.java | 50 + .../org/onosproject/store/device/impl/PortKey.java | 79 + .../store/device/impl/package-info.java | 20 + .../store/ecmap/AntiEntropyAdvertisement.java | 71 + .../ecmap/EventuallyConsistentMapBuilderImpl.java | 161 ++ .../store/ecmap/EventuallyConsistentMapImpl.java | 678 ++++++++ .../store/ecmap/MapDbPersistentStore.java | 103 ++ .../java/org/onosproject/store/ecmap/MapValue.java | 158 ++ .../onosproject/store/ecmap/PersistentStore.java | 47 + .../org/onosproject/store/ecmap/UpdateEntry.java | 80 + .../org/onosproject/store/ecmap/package-info.java | 21 + .../org/onosproject/store/flow/ReplicaInfo.java | 85 + .../onosproject/store/flow/ReplicaInfoEvent.java | 64 + .../store/flow/ReplicaInfoEventListener.java | 26 + .../onosproject/store/flow/ReplicaInfoService.java | 48 + .../store/flow/impl/FlowStoreMessageSubjects.java | 43 + .../flow/impl/NewDistributedFlowRuleStore.java | 789 +++++++++ .../store/flow/impl/ReplicaInfoManager.java | 123 ++ .../onosproject/store/flow/impl/package-info.java | 21 + .../org/onosproject/store/flow/package-info.java | 20 + .../impl/DistributedFlowObjectiveStore.java | 102 ++ .../store/flowobjective/impl/package-info.java | 20 + .../store/group/impl/DistributedGroupStore.java | 1304 +++++++++++++++ .../store/group/impl/GroupStoreMessage.java | 184 +++ .../group/impl/GroupStoreMessageSubjects.java | 28 + .../onosproject/store/group/impl/package-info.java | 19 + .../onosproject/store/host/impl/ECHostStore.java | 267 ++++ .../onosproject/store/host/impl/package-info.java | 20 + .../onosproject/store/impl/LogicalTimestamp.java | 68 + .../store/impl/MastershipBasedTimestamp.java | 117 ++ .../org/onosproject/store/impl/Timestamped.java | 119 ++ .../org/onosproject/store/impl/package-info.java | 20 + .../store/intent/impl/GossipIntentStore.java | 334 ++++ .../onosproject/store/intent/impl/PartitionId.java | 68 + .../store/intent/impl/PartitionManager.java | 243 +++ .../store/intent/impl/package-info.java | 20 + .../onosproject/store/link/impl/ECLinkStore.java | 390 +++++ .../store/link/impl/GossipLinkStore.java | 903 +++++++++++ .../link/impl/GossipLinkStoreMessageSubjects.java | 35 + .../store/link/impl/InternalLinkEvent.java | 61 + .../store/link/impl/InternalLinkRemovedEvent.java | 64 + .../link/impl/LinkAntiEntropyAdvertisement.java | 63 + .../store/link/impl/LinkFragmentId.java | 77 + .../store/link/impl/LinkInjectedEvent.java | 38 + .../org/onosproject/store/link/impl/Provided.java | 68 + .../onosproject/store/link/impl/package-info.java | 20 + .../impl/ConsistentDeviceMastershipStore.java | 419 +++++ .../store/mastership/impl/RoleValue.java | 179 +++ .../store/mastership/impl/RoleValueSerializer.java | 67 + .../store/mastership/impl/package-info.java | 20 + .../newresource/impl/ConsistentResourceStore.java | 349 ++++ .../store/newresource/impl/package-info.java | 20 + .../store/packet/impl/DistributedPacketStore.java | 207 +++ .../store/packet/impl/package-info.java | 20 + .../proxyarp/impl/DistributedProxyArpStore.java | 174 ++ .../impl/ConsistentDeviceResourceStore.java | 225 +++ .../resource/impl/ConsistentLinkResourceStore.java | 503 ++++++ .../store/resource/impl/package-info.java | 20 + .../custom/ClusterMessageSerializer.java | 53 + .../custom/DistributedStoreSerializers.java | 42 + .../custom/MastershipBasedTimestampSerializer.java | 51 + .../custom/MessageSubjectSerializer.java | 46 + .../store/serializers/custom/package-info.java | 22 + .../statistic/impl/DistributedStatisticStore.java | 317 ++++ .../impl/StatisticStoreMessageSubjects.java | 30 + .../store/statistic/impl/package-info.java | 20 + .../topology/impl/DistributedTopologyStore.java | 254 +++ .../onosproject/store/topology/impl/PathKey.java | 55 + .../store/topology/impl/package-info.java | 20 + .../store/cluster/StaticClusterService.java | 55 + .../impl/ClusterCommunicationManagerTest.java | 142 ++ .../impl/DistributedNetworkConfigStoreTest.java | 127 ++ .../store/consistent/impl/MatchTest.java | 52 + .../store/consistent/impl/ResultTest.java | 42 + .../store/consistent/impl/UpdateResultTest.java | 84 + .../store/device/impl/DeviceFragmentIdTest.java | 48 + .../store/device/impl/GossipDeviceStoreTest.java | 917 +++++++++++ .../store/device/impl/PortFragmentIdTest.java | 61 + .../ecmap/EventuallyConsistentMapImplTest.java | 909 +++++++++++ .../org/onosproject/store/ecmap/MapValueTest.java | 79 + .../store/flow/impl/ReplicaInfoManagerTest.java | 167 ++ .../impl/DistributedFlowObjectiveStoreTest.java | 63 + .../group/impl/DistributedGroupStoreTest.java | 420 +++++ .../store/impl/MastershipBasedTimestampTest.java | 110 ++ .../onosproject/store/impl/TimestampedTest.java | 109 ++ .../store/intent/impl/GossipIntentStoreTest.java | 234 +++ .../store/intent/impl/PartitionManagerTest.java | 329 ++++ .../store/link/impl/GossipLinkStoreTest.java | 632 ++++++++ .../store/link/impl/LinkFragmentIdTest.java | 63 + .../impl/DistributedMastershipStoreTest.java | 286 ++++ .../store/mastership/impl/RoleValueTest.java | 46 + .../impl/HazelcastLinkResourceStoreTest.java | 227 +++ framework/src/onos/core/store/pom.xml | 54 + framework/src/onos/core/store/serializers/pom.xml | 50 + .../store/serializers/AnnotationsSerializer.java | 32 + .../store/serializers/ArraysAsListSerializer.java | 49 + .../store/serializers/ConnectPointSerializer.java | 51 + .../DefaultApplicationIdSerializer.java | 49 + .../store/serializers/DefaultLinkSerializer.java | 61 + .../DefaultOutboundPacketSerializer.java | 58 + .../store/serializers/DefaultPortSerializer.java | 65 + .../store/serializers/DeviceIdSerializer.java | 48 + .../store/serializers/HostLocationSerializer.java | 55 + .../store/serializers/ImmutableListSerializer.java | 55 + .../store/serializers/ImmutableMapSerializer.java | 58 + .../store/serializers/ImmutableSetSerializer.java | 55 + .../store/serializers/Ip4AddressSerializer.java | 52 + .../store/serializers/Ip4PrefixSerializer.java | 57 + .../store/serializers/Ip6AddressSerializer.java | 52 + .../store/serializers/Ip6PrefixSerializer.java | 57 + .../store/serializers/IpAddressSerializer.java | 58 + .../store/serializers/IpPrefixSerializer.java | 64 + .../store/serializers/KryoNamespaces.java | 479 ++++++ .../store/serializers/KryoSerializer.java | 86 + .../store/serializers/LinkKeySerializer.java | 51 + .../store/serializers/MacAddressSerializer.java | 47 + .../serializers/MastershipTermSerializer.java | 51 + .../store/serializers/NodeIdSerializer.java | 48 + .../store/serializers/PortNumberSerializer.java | 56 + .../store/serializers/ProviderIdSerializer.java | 53 + .../store/serializers/StoreSerializer.java | 78 + .../store/serializers/URISerializer.java | 46 + .../store/serializers/package-info.java | 20 + .../store/serializers/KryoSerializerTest.java | 470 ++++++ 1309 files changed, 146141 insertions(+) create mode 100644 framework/src/onos/core/api/pom.xml create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationAdminService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationException.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationState.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/app/DefaultApplicationDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/app/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ConfigProperty.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cfg/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterAdminService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterDefinitionService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterEventListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ControllerNode.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ControllerNodeToNodeId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/DefaultControllerNode.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/Leadership.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/LeadershipEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/LeadershipEventListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/LeadershipService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/NodeId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/RoleInfo.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/cluster/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/codec/CodecContext.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/codec/CodecService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/codec/JsonCodec.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/codec/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/Application.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/ApplicationId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/ApplicationIdStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/ApplicationRole.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/CoreService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultApplication.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultApplicationId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultGroupId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/GroupId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/IdBlock.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/IdBlockStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/IdGenerator.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/MetricsHelper.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/UnavailableIdException.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/Version.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/core/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/event/AbstractEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/event/AbstractListenerManager.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/event/DefaultEventSinkRegistry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/event/Event.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/event/EventDeliveryService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/event/EventDispatcher.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/event/EventFilter.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/event/EventListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/event/EventSink.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/event/EventSinkRegistry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/event/ListenerRegistry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/event/ListenerService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/event/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipAdminService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipTerm.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipTermService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/mastership/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractAnnotated.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractElement.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractModel.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/Annotated.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/Annotations.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationsUtil.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/ChannelSpacing.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/ConnectPoint.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultAnnotations.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultDevice.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultEdgeLink.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultHost.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultLink.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultPath.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultPort.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/Description.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/Device.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/DeviceId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/EdgeLink.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/Element.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/ElementId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/GridType.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/Host.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/HostId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/HostLocation.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/IndexedLambda.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/IpElementId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/Lambda.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/Link.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/LinkKey.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/MastershipRole.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/MutableAnnotations.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/NetTools.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/NetworkResource.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/OchPort.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/OchSignal.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/OchSignalType.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/OduCltPort.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/OduSignalType.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/OmsPort.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/Path.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/Port.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/PortNumber.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/Provided.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/SparseAnnotations.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeName.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/DefaultBridgeDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/DefaultNextGroup.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/DefaultTunnelDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/IpTunnelEndPoint.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/MplsQuery.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/NextGroup.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/Pipeliner.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/PipelinerContext.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/PortAdmin.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/PortConfig.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/QueueConfig.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/QueueInfo.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelConfig.java create mode 100755 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelEndPoint.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelName.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/VlanQuery.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/Config.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/ConfigApplyDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/ConfigFactory.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/ConfigOperator.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigRegistry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/SubjectFactory.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/AllowedEntityConfig.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicDeviceConfig.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicElementConfig.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicHostConfig.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicLinkConfig.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/OpticalPortConfig.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/SubjectFactories.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/config/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DefaultDeviceDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DefaultPortDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DefaultPortStatistics.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceAdminService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceClockService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceProvider.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceProviderRegistry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceProviderService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/OduCltPortDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/OmsPortDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/PortDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/PortStatistics.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/device/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/AbstractBehaviour.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/AbstractHandlerBehaviour.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/Behaviour.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriver.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverData.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverHandler.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverProvider.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverProviderService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/Driver.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverAdminService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverConnect.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverData.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverHandler.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverProvider.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverResolver.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/HandlerBehaviour.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/XmlDriverLoader.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/EdgePortEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/EdgePortListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/EdgePortService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/BatchOperation.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/BatchOperationEntry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/BatchOperationResult.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/CompletedBatchOperation.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultFlowEntry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultFlowRule.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowEntry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchEntry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchOperation.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchRequest.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleExtPayLoad.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperation.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperations.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperationsContext.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProvider.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderRegistry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/StoredFlowEntry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Treatment.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/EthCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/EthTypeCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPDscpCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPEcnCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPProtocolCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6ExthdrFlagsCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6FlowLabelCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6NDLinkLayerAddressCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6NDTargetAddressCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IcmpCodeCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IcmpTypeCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Icmpv6CodeCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Icmpv6TypeCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IndexedLambdaCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/LambdaCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/MetadataCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/MplsBosCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/MplsCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OchSignalCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OchSignalTypeCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OpticalSignalTypeCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/PortCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/SctpPortCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/TcpPortCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/TunnelIdCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/UdpPortCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/VlanIdCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/VlanPcpCriterion.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L0ModificationInstruction.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L2ModificationInstruction.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L3ModificationInstruction.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L4ModificationInstruction.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultForwardingObjective.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ForwardingObjective.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/NextObjective.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/Objective.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ObjectiveContext.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ObjectiveError.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ObjectiveEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroup.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupKey.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/Group.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupBucket.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupBuckets.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupKey.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupOperation.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupOperations.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupProvider.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupProviderRegistry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupProviderService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/StoredGroupBucketEntry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/StoredGroupEntry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/group/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/host/DefaultHostDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostAdminService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProvider.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderRegistry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/host/InterfaceIpAddress.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/host/PortAddresses.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/host/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/ConnectivityIntent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Constraint.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/HostToHostIntent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Intent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentBatchDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentClockService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentCompiler.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentData.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentException.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentExtensionService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentOperation.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentState.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Key.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/LinkCollectionIntent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/MplsIntent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/MplsPathIntent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/MultiPointToSinglePointIntent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/OpticalCircuitIntent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/OpticalConnectivityIntent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/OpticalPathIntent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PartitionEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PartitionEventListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PartitionService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PathIntent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PointToPointIntent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/SinglePointToMultiPointIntent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/TwoWayP2PIntent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/AnnotationConstraint.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/AsymmetricPathConstraint.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BandwidthConstraint.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BooleanConstraint.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/LambdaConstraint.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/LatencyConstraint.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/LinkTypeConstraint.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/ObstacleConstraint.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/PartialFailureConstraint.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/WaypointConstraint.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/link/DefaultLinkDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkAdminService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkProvider.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkProviderRegistry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkProviderService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/link/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/Band.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/BandEntry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultBand.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeter.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/Meter.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterContext.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterEntry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterFailReason.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterOperation.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterOperations.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterProvider.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterProviderRegistry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterProviderService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterRequest.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterState.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStoreResult.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceAdminService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceAllocation.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceConsumer.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourcePath.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultInboundPacket.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultOutboundPacket.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultPacketContext.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultPacketRequest.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/InboundPacket.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/OutboundPacket.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketContext.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketPriority.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProcessor.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProvider.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProviderRegistry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProviderService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketRequest.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractListenerProviderRegistry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractProvider.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractProviderRegistry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractProviderService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/Provider.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/ProviderId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/ProviderRegistry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/ProviderService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceAllocation.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceAllocationException.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceException.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceRequest.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceType.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResource.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceAllocation.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceRequest.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceAllocations.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResource.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceAllocation.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceRequest.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResource.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceAllocations.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResources.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabel.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceAllocation.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/DefaultLoad.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/Load.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/StatisticService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/StatisticStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/ClusterId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultGraphDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultTopologyCluster.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultTopologyEdge.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultTopologyVertex.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/GraphDescription.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/LinkWeight.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/Topology.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyCluster.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyEdge.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyGraph.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyProvider.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyProviderRegistry.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyProviderService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyVertex.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/rest/AbstractApiDocRegistrator.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/rest/AbstractInjectionResource.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/rest/AbstractWebResource.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/rest/ApiDocProvider.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/rest/ApiDocService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/rest/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/security/AppGuard.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/security/AppPermission.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/security/Permission.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/security/SecurityAdminService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/security/SecurityUtil.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/security/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/AbstractStore.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/Store.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/StoreDelegate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/Timestamp.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/ClusterCommunicationService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/ClusterMessage.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/ClusterMessageHandler.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/Endpoint.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/MessageSubject.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/MessagingService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncAtomicCounter.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncConsistentMap.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounter.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounterBuilder.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValue.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValueBuilder.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValueEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValueEventListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/ConsistentMap.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/ConsistentMapBuilder.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/ConsistentMapException.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DatabaseUpdate.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedQueue.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedQueueBuilder.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedSet.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedSetBuilder.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMap.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMapBuilder.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMapEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMapListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/LogicalClockService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MapEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MapEventListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MapInfo.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MultiValuedTimestamp.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/PartitionInfo.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/Serializer.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/SetEvent.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/SetEventListener.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/StorageAdminService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/StorageException.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/StorageService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/Transaction.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContext.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContextBuilder.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionException.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionalMap.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/Versioned.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/WallClockTimestamp.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/store/service/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/JsonUtils.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/RequestHandler.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiConnection.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiExtension.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiExtensionService.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiMessageHandler.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiMessageHandlerFactory.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlayFactory.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiView.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiViewHidden.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/CellComparator.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/CellFormatter.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/TableModel.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/TableRequestHandler.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/TableUtils.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AbstractCellComparator.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AbstractCellFormatter.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AppIdFormatter.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/ConnectPointFormatter.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/DefaultCellComparator.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/DefaultCellFormatter.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/EnumFormatter.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/HexFormatter.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/HostLocationFormatter.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/TimeFormatter.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/package-info.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/AbstractHighlight.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BaseLink.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BaseLinkMap.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BiLink.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BiLinkMap.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/ButtonId.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/DeviceHighlight.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/Highlights.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/HostHighlight.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/LinkHighlight.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/Mod.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeHighlight.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeSelection.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/PropertyPanel.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoConstants.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoElementType.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoUtils.java create mode 100644 framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/package-info.java create mode 100644 framework/src/onos/core/api/src/main/javadoc/org/onosproject/net/flow/doc-files/flow-design.png create mode 100644 framework/src/onos/core/api/src/main/javadoc/org/onosproject/net/intent/doc-files/intent-design.png create mode 100644 framework/src/onos/core/api/src/main/javadoc/org/onosproject/net/intent/doc-files/intent-states.png create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/TestApplicationId.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/VersionTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationAdminServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationEventTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationExceptionTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationStoreAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/app/DefaultApplicationDescriptionTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ConfigPropertyTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/cluster/ClusterServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/cluster/ControllerNodeToNodeIdTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/cluster/LeadershipEventTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/cluster/LeadershipServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/cluster/LeadershipTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/cluster/RoleInfoTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/codec/JsonCodecTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/core/ApplicationIdStoreAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/core/CoreServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/core/DefaultApplicationTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/core/DefaultGroupIdTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/core/UnavailableIdExceptionTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/event/AbstractEventTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/event/BrokenListener.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/event/DefaultEventSinkRegistryTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/event/EventDeliveryServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/event/ListenerRegistryTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/event/TestEvent.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/event/TestListener.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/event/TestListenerRegistry.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/mastership/MastershipServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/mastership/MastershipTermTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/ConnectPointTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultAnnotationsTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultDeviceTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultEdgeLinkTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultHostTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultLinkTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultPortTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/DeviceIdTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/HostIdTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/IndexedLambdaTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/LinkKeyTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/NetTestTools.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/OchSignalTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/PortNumberTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/TestDeviceParams.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigRegistryAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DefaultDeviceDescriptionTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DefaultPortStatisticsTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DeviceClockServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DeviceEventTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DeviceServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverDataTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverHandlerTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverProviderTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviour.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourImpl.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourNoConstructorImpl.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourTwo.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourTwoImpl.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/XmlDriverLoaderTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/BatchOperationTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultFlowEntryTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultFlowRuleTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficTreatmentTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowIdTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleBatchOperationTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleBatchRequestTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleEventTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleExtPayLoadTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/instructions/InstructionsTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/flowobjective/ObjectiveTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/group/DefaultGroupDescriptionTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/group/DefaultGroupTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/group/GroupBucketTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/group/GroupOperationTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/host/DefaultHostDecriptionTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/host/HostEventTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/host/HostServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/host/InterfaceIpAddressTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/host/PortAddressesTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/AbstractIntentTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/ConnectivityIntentTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/HostToHostIntentTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentDataTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentExceptionTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentIdTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentServiceTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/KeyTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/LinkCollectionIntentTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MockIdGenerator.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MplsIntentTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MplsPathIntentTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MultiPointToSinglePointIntentTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/OpticalConnectivityIntentTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/OpticalPathIntentTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/PartitionServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/PathIntentTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/SinglePointToMultiPointIntentTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestInstallableIntent.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestIntent.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestSubclassInstallableIntent.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestSubclassIntent.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestTools.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestableIntentService.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TwoWayP2PIntentTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/AnnotationConstraintTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/ConstraintObjectsTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/LatencyConstraintTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/ObstacleConstraintTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/WaypointConstraintTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/link/DefaultLinkDescriptionTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/link/LinkEventTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/link/LinkServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/meter/DefaultMeterTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/meter/MeterOperationTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourceAllocationTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourcePathTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultInboundPacketTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultOutboundPacketTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultPacketContextTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/AbstractProviderRegistryTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/AbstractProviderTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/ProviderIdTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/TestProvider.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/resource/MplsObjectsTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/statistic/DefaultLoadTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/statistic/StatisticServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/ClusterIdTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultGraphDescriptionTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultTopologyClusterTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultTopologyEdgeTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultTopologyVertexTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/ClusterCommunicationServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/ClusterMessageTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/EndpointTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/MessageSubjectTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/service/AtomicValueEventTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/service/ConsistentMapAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/service/DatabaseUpdateTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/service/EventuallyConsistentMapAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/service/EventuallyConsistentMapEventTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/service/MapEventTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/service/MultiValuedTimestampTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/service/SetEventTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/service/StorageServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestAtomicCounter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestConsistentMap.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestEventuallyConsistentMap.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestStorageService.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/service/VersionedTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/store/service/WallClockTimestampTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/UiExtensionServiceAdapter.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/UiExtensionTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/TableModelTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/TableUtilsTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/AbstractCellComparatorTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/AbstractCellFormatterTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/AppIdFormatterTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/ConnectPointFormatterTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/DefaultCellComparatorTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/DefaultCellFormatterTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/EnumFormatterTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/HexFormatterTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/HostLocationFormatterTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/TimeFormatterTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/BiLinkMapTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTestBase.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/ButtonIdTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/HighlightsTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/LinkHighlightTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/ModTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/NodeSelectionTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/PropertyPanelTest.java create mode 100644 framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/TopoJsonTest.java create mode 100644 framework/src/onos/core/api/src/test/resources/css.html create mode 100644 framework/src/onos/core/api/src/test/resources/custom/css.html create mode 100644 framework/src/onos/core/api/src/test/resources/custom/js.html create mode 100644 framework/src/onos/core/api/src/test/resources/js.html create mode 100644 framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.1.xml create mode 100644 framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.bad.xml create mode 100644 framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.noclass.xml create mode 100644 framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.noconstructor.xml create mode 100644 framework/src/onos/core/common/pom.xml create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/AnnotatedCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/AnnotationsCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ApplicationCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ConnectPointCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ConnectivityIntentCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ConstraintCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ControllerNodeCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeConstraintCodecHelper.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DeviceCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DriverCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeConstraintCodecHelper.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EthernetCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/FlowEntryCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/FlowRuleCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/GroupBucketCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/GroupCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/HostLocationCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/HostToHostIntentCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/IntentCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/LinkCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/LoadCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/PathCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/PointToPointIntentCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/PortCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TopologyClusterCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TopologyCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TrafficSelectorCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TrafficTreatmentCodec.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/package-info.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopology.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopologyGraph.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/common/app/package-info.java create mode 100644 framework/src/onos/core/common/src/main/java/org/onosproject/common/package-info.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ConnectPointJsonMatcher.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ConstraintCodecTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DeviceCodecTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DriverCodecTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DriverJsonMatcher.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/EthernetCodecTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/EthernetJsonMatcher.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupBucketJsonMatcher.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupCodecTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupJsonMatcher.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ImmutableCodecsTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentCodecTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/JsonCodecUtils.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/LinkCodecTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/LoadCodecTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/MockCodecContext.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/PortCodecTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/common/DefaultTopologyTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/common/app/ApplicationArchiveTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/common/event/impl/TestEventDispatcher.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/PathKey.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationIdStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationStoreTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleClusterStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleComponentConfigStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleDeviceStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleDeviceStoreTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleGroupStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleGroupStoreTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleIdBlockStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleIntentStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLeadershipManager.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkResourceStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkResourceStoreTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkStoreTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleMastershipStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleMastershipStoreTest.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimplePacketStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleStatisticStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SystemClockTimestamp.java create mode 100644 framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/package-info.java create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/AnnotationConstraint.json create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/AsymmetricPathConstraint.json create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/BandwidthConstraint.json create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/HostToHostIntent.json create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/LambdaConstraint.json create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/LatencyConstraint.json create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/LinkTypeConstraint.json create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/ObstacleConstraint.json create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/PointToPointIntent.json create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/WaypointConstraint.json create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/criteria-flow.json create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/instructions-flow.json create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/sigid-flow.json create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/simple-flow.json create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/common/app/app.xml create mode 100644 framework/src/onos/core/common/src/test/resources/org/onosproject/common/app/app.zip create mode 100644 framework/src/onos/core/net/pom.xml create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/app/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ConfigPropertyDefinitions.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/MastershipManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/BlockAllocatorBasedIdGenerator.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/CoreManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/IdBlockAllocator.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/MetricsManagerComponent.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/StoreBasedIdBlockAllocator.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/event/impl/CoreEventDispatcher.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/event/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/BasicNetworkConfigs.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigLoader.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/BasicDeviceOperator.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/driver/impl/DriverManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/driver/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/edgeservice/impl/EdgeManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/edgeservice/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FilterTable.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionTree.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/ForwardTable.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/ForwardUpdateTable.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/NextTable.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/group/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/BasicHostOperator.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/CompilerRegistry.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentAccumulator.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCompilationException.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentInstallationException.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentProcessor.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentRemovalException.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTracker.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTrackerService.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/PathNotFoundException.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/TopologyChangeDelegate.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/ConnectivityIntentCompiler.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/HostToHostIntentCompiler.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsIntentCompiler.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompiler.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/SinglePointToMultiPointIntentCompiler.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/TwoWayP2PIntentCompiler.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Compiling.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Corrupt.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Failed.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/FinalIntentProcessPhase.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallRequest.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Installing.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/IntentProcessPhase.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/IntentWorker.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/PurgeRequest.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawRequest.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawing.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawn.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/BasicLinkOperator.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceDeviceListener.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceLinkListener.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceRegistrar.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/proxyarp/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/DeviceResourceManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/StatisticManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/DefaultTopologyProvider.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java create mode 100644 framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/package-info.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/FeaturesServiceAdapter.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/cfg/impl/ConfigPropertyDefinitionsTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/cluster/impl/MastershipManagerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/core/impl/DummyIdBlockAllocator.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/core/impl/IdBlockAllocatorBasedIdGeneratorTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/core/impl/TestCoreManager.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/event/impl/CoreEventDispatcherTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/config/impl/NetworkConfigManagerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/device/impl/BasicDeviceOperatorTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/device/impl/DeviceManagerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/device/impl/OpticalPortOperatorTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/edgeservice/impl/EdgeManagerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/flowobjective/impl/FlowObjectiveCompositionTreeTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/BasicHostOperatorTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostManagerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/host/impl/HostMonitorTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/LinksHaveEntryWithSourceDestinationPairMatcher.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentAccumulatorTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTestMock.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/MockFlowRuleService.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/ObjectiveTrackerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/HostToHostIntentCompilerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompilerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsIntentCompilerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompilerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompilerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompilerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/intent/impl/phase/CompilingTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/link/impl/BasicLinkOperatorTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/link/impl/LinkManagerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/proxyarp/impl/ProxyArpManagerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/DefaultTopologyProviderTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/PathManagerTest.java create mode 100644 framework/src/onos/core/net/src/test/java/org/onosproject/net/topology/impl/TopologyManagerTest.java create mode 100644 framework/src/onos/core/pom.xml create mode 100644 framework/src/onos/core/security/pom.xml create mode 100644 framework/src/onos/core/security/src/main/java/org/onosproject/security/impl/DefaultPolicyBuilder.java create mode 100644 framework/src/onos/core/security/src/main/java/org/onosproject/security/impl/SecurityModeManager.java create mode 100644 framework/src/onos/core/security/src/main/java/org/onosproject/security/impl/package-info.java create mode 100644 framework/src/onos/core/security/src/main/java/org/onosproject/security/store/DistributedSecurityModeStore.java create mode 100644 framework/src/onos/core/security/src/main/java/org/onosproject/security/store/SecurityInfo.java create mode 100644 framework/src/onos/core/security/src/main/java/org/onosproject/security/store/SecurityModeEvent.java create mode 100644 framework/src/onos/core/security/src/main/java/org/onosproject/security/store/SecurityModeListener.java create mode 100644 framework/src/onos/core/security/src/main/java/org/onosproject/security/store/SecurityModeState.java create mode 100644 framework/src/onos/core/security/src/main/java/org/onosproject/security/store/SecurityModeStore.java create mode 100644 framework/src/onos/core/security/src/main/java/org/onosproject/security/store/SecurityModeStoreDelegate.java create mode 100644 framework/src/onos/core/store/dist/pom.xml create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/app/GossipApplicationStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/app/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cfg/GossipComponentConfigStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cfg/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinition.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionManager.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterDefinitionStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterManagementMessageSubjects.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterMembershipEvent.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterMembershipEventType.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/ClusterNodesDelegate.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/DistributedClusterStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/NodeInfo.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/PhiAccrualFailureDetector.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/ClusterCommunicationManager.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/IOLoopMessagingManager.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/config/impl/DistributedNetworkConfigStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/config/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/AsyncCachingConsistentMap.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/CommitResponse.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/ConsistentMapBackedJavaMap.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/CopycatCommunicationProtocol.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseConfig.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinition.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseDefinitionStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabasePartitioner.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseSerializer.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncAtomicCounter.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncConsistentMap.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicCounter.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicCounterBuilder.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicValue.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAtomicValueBuilder.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultConsistentMap.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultConsistentMapBuilder.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDistributedQueue.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDistributedQueueBuilder.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDistributedSet.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDistributedSetBuilder.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransaction.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionContext.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionContextBuilder.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionalMap.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DistributedLeadershipManager.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Match.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/MeteringAgent.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Partitioner.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Result.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/SimpleKeyHashPartitioner.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/SimpleTableHashPartitioner.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/StateMachineUpdate.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/TransactionManager.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/UpdateResult.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/core/impl/AppIdEvent.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/core/impl/AppIdStoreDelegate.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/core/impl/ConsistentApplicationIdStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/core/impl/ConsistentIdBlockStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/core/impl/LogicalClockManager.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/core/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/DeviceAntiEntropyAdvertisement.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/DeviceAntiEntropyRequest.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/DeviceClockManager.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/DeviceDescriptions.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/DeviceFragmentId.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/DeviceInjectedEvent.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/DeviceKey.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/ECDeviceStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/GossipDeviceStoreMessageSubjects.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/InternalDeviceEvent.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/InternalDeviceEventSerializer.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/InternalDeviceOfflineEvent.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/InternalDeviceOfflineEventSerializer.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/InternalDeviceRemovedEvent.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/InternalPortEvent.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/InternalPortEventSerializer.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/InternalPortStatusEvent.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/InternalPortStatusEventSerializer.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/PortFragmentId.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/PortInjectedEvent.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/PortKey.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/device/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/AntiEntropyAdvertisement.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/EventuallyConsistentMapBuilderImpl.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/EventuallyConsistentMapImpl.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/MapDbPersistentStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/MapValue.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/PersistentStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/UpdateEntry.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/ecmap/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/ReplicaInfo.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/ReplicaInfoEvent.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/ReplicaInfoEventListener.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/ReplicaInfoService.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/FlowStoreMessageSubjects.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/NewDistributedFlowRuleStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ReplicaInfoManager.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flow/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flowobjective/impl/DistributedFlowObjectiveStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/flowobjective/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/GroupStoreMessage.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/GroupStoreMessageSubjects.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/group/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/host/impl/ECHostStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/host/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/impl/LogicalTimestamp.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/impl/MastershipBasedTimestamp.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/impl/Timestamped.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/GossipIntentStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/PartitionId.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/PartitionManager.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/intent/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/ECLinkStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/GossipLinkStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/GossipLinkStoreMessageSubjects.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/InternalLinkEvent.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/InternalLinkRemovedEvent.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/LinkAntiEntropyAdvertisement.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/LinkFragmentId.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/LinkInjectedEvent.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/Provided.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/link/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/mastership/impl/ConsistentDeviceMastershipStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/mastership/impl/RoleValue.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/mastership/impl/RoleValueSerializer.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/mastership/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/newresource/impl/ConsistentResourceStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/newresource/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/packet/impl/DistributedPacketStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/packet/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/proxyarp/impl/DistributedProxyArpStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentDeviceResourceStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentLinkResourceStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/resource/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/serializers/custom/ClusterMessageSerializer.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/serializers/custom/DistributedStoreSerializers.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/serializers/custom/MastershipBasedTimestampSerializer.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/serializers/custom/MessageSubjectSerializer.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/serializers/custom/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/statistic/impl/DistributedStatisticStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/statistic/impl/StatisticStoreMessageSubjects.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/statistic/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/DistributedTopologyStore.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/PathKey.java create mode 100644 framework/src/onos/core/store/dist/src/main/java/org/onosproject/store/topology/impl/package-info.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/cluster/StaticClusterService.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/cluster/messaging/impl/ClusterCommunicationManagerTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/config/impl/DistributedNetworkConfigStoreTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/consistent/impl/MatchTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/consistent/impl/ResultTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/consistent/impl/UpdateResultTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/device/impl/DeviceFragmentIdTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/device/impl/GossipDeviceStoreTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/device/impl/PortFragmentIdTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/ecmap/EventuallyConsistentMapImplTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/ecmap/MapValueTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/flow/impl/ReplicaInfoManagerTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/flowobjective/impl/DistributedFlowObjectiveStoreTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/group/impl/DistributedGroupStoreTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/impl/MastershipBasedTimestampTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/impl/TimestampedTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/intent/impl/GossipIntentStoreTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/intent/impl/PartitionManagerTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/link/impl/GossipLinkStoreTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/link/impl/LinkFragmentIdTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/mastership/impl/DistributedMastershipStoreTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/mastership/impl/RoleValueTest.java create mode 100644 framework/src/onos/core/store/dist/src/test/java/org/onosproject/store/resource/impl/HazelcastLinkResourceStoreTest.java create mode 100644 framework/src/onos/core/store/pom.xml create mode 100644 framework/src/onos/core/store/serializers/pom.xml create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/AnnotationsSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ArraysAsListSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ConnectPointSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/DefaultApplicationIdSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/DefaultLinkSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/DefaultOutboundPacketSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/DefaultPortSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/DeviceIdSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/HostLocationSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ImmutableListSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ImmutableMapSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ImmutableSetSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/Ip4AddressSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/Ip4PrefixSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/Ip6AddressSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/Ip6PrefixSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/IpAddressSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/IpPrefixSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/LinkKeySerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/MacAddressSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/MastershipTermSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/NodeIdSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/PortNumberSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/ProviderIdSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/StoreSerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/URISerializer.java create mode 100644 framework/src/onos/core/store/serializers/src/main/java/org/onosproject/store/serializers/package-info.java create mode 100644 framework/src/onos/core/store/serializers/src/test/java/org/onosproject/store/serializers/KryoSerializerTest.java (limited to 'framework/src/onos/core') diff --git a/framework/src/onos/core/api/pom.xml b/framework/src/onos/core/api/pom.xml new file mode 100644 index 00000000..7cfb4acc --- /dev/null +++ b/framework/src/onos/core/api/pom.xml @@ -0,0 +1,68 @@ + + + + 4.0.0 + + + org.onosproject + onos-core + 1.3.0-SNAPSHOT + ../pom.xml + + + onos-api + bundle + + ONOS network control API + + + + joda-time + joda-time + + + commons-configuration + commons-configuration + + + commons-collections + commons-collections + + + com.google.guava + guava-testlib + test + + + org.easymock + easymock + test + + + org.onosproject + onlab-osgi + + + org.onosproject + onlab-rest + ${project.version} + + + + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationAdminService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationAdminService.java new file mode 100644 index 00000000..3713e218 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationAdminService.java @@ -0,0 +1,70 @@ +/* + * 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.app; + +import org.onosproject.core.Application; +import org.onosproject.core.ApplicationId; +import org.onosproject.security.Permission; + +import java.io.InputStream; +import java.util.Set; + +/** + * Service for managing network control applications. + */ +public interface ApplicationAdminService extends ApplicationService { + + /** + * Installs the application contained in the specified application archive + * input stream. This can be either a ZIP stream containing a compressed + * application archive or a plain XML stream containing just the + * {@code app.xml} application descriptor file. + * + * @param appDescStream application descriptor input stream + * @return installed application descriptor + * @throws org.onosproject.app.ApplicationException if unable to read the app archive stream + */ + Application install(InputStream appDescStream); + + /** + * Uninstalls the specified application. + * + * @param appId application identifier + */ + void uninstall(ApplicationId appId); + + /** + * Activates the specified application. + * + * @param appId application identifier + */ + void activate(ApplicationId appId); + + /** + * Deactivates the specified application. + * + * @param appId application identifier + */ + void deactivate(ApplicationId appId); + + /** + * Updates the permissions granted to the applications. + * + * @param appId application identifier + * @param permissions set of granted permissions + */ + void setPermissions(ApplicationId appId, Set permissions); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationDescription.java new file mode 100644 index 00000000..2561280b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationDescription.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.app; + +import org.onosproject.core.ApplicationRole; +import org.onosproject.core.Version; +import org.onosproject.security.Permission; + +import java.net.URI; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * Description of a network control/management application. + */ +public interface ApplicationDescription { + + /** + * Returns the application name id. + * + * @return application identifier + */ + String name(); + + /** + * Returns the application version. + * + * @return application version + */ + Version version(); + + /** + * Returns description of the application. + * + * @return application description text + */ + String description(); + + /** + * Returns the name of the application origin, group or company. + * + * @return application origin + */ + String origin(); + + /** + * Returns the role of the application. + * + * @return application role + */ + ApplicationRole role(); + + /** + * Returns the permissions requested by the application. + * + * @return requested permissions + */ + Set permissions(); + + /** + * Returns the feature repository URI. Null value signifies that the + * application did not provide its own features repository. + * + * @return optional feature repo URL + */ + Optional featuresRepo(); + + /** + * Returns the list of features comprising the application. At least one + * feature must be given. + * + * @return application features + */ + List features(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationEvent.java new file mode 100644 index 00000000..5bf1323d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationEvent.java @@ -0,0 +1,75 @@ +/* + * 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.app; + +import org.onosproject.core.Application; +import org.onosproject.event.AbstractEvent; + +/** + * Describes application lifecycle event. + */ +public class ApplicationEvent extends AbstractEvent { + + public enum Type { + /** + * Signifies that an application has been installed. + */ + APP_INSTALLED, + + /** + * Signifies that an application has been activated. + */ + APP_ACTIVATED, + + /** + * Signifies that an application has been deactivated. + */ + APP_DEACTIVATED, + + /** + * Signifies that an application has been uninstalled. + */ + APP_UNINSTALLED, + + /** + * Signifies that application granted permissions have changed. + */ + APP_PERMISSIONS_CHANGED + } + + /** + * Creates an event of a given type and for the specified app and the + * current time. + * + * @param type app event type + * @param app event app subject + */ + public ApplicationEvent(Type type, Application app) { + super(type, app); + } + + /** + * Creates an event of a given type and for the specified app and time. + * + * @param type app event type + * @param app event app subject + * @param time occurrence time + */ + public ApplicationEvent(Type type, Application app, long time) { + super(type, app, time); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationException.java b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationException.java new file mode 100644 index 00000000..2888c70b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationException.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.app; + +/** + * Represents class of errors related to application management. + */ +public class ApplicationException extends RuntimeException { + + private static final long serialVersionUID = -2287403908433720122L; + + /** + * Constructs an exception with no message and no underlying cause. + */ + public ApplicationException() { + } + + /** + * Constructs an exception with the specified message. + * + * @param message the message describing the specific nature of the error + */ + public ApplicationException(String message) { + super(message); + } + + /** + * Constructs an exception with the specified message and the underlying cause. + * + * @param message the message describing the specific nature of the error + * @param cause the underlying cause of this error + */ + public ApplicationException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationListener.java new file mode 100644 index 00000000..7a680572 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationListener.java @@ -0,0 +1,24 @@ +/* + * 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.app; + +import org.onosproject.event.EventListener; + +/** + * Entity capable of receiving application related events. + */ +public interface ApplicationListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationService.java new file mode 100644 index 00000000..73dcc86c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationService.java @@ -0,0 +1,70 @@ +/* + * 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.app; + +import org.onosproject.core.Application; +import org.onosproject.core.ApplicationId; +import org.onosproject.event.ListenerService; +import org.onosproject.security.Permission; + +import java.util.Set; + +/** + * Service for inspecting inventory of network control applications. + */ +public interface ApplicationService + extends ListenerService { + + /** + * Returns the set of all installed applications. + * + * @return set of installed apps + */ + Set getApplications(); + + /** + * Returns the registered id of the application with the given name. + * + * @param name application name + * @return registered application id + */ + ApplicationId getId(String name); + + /** + * Returns the application with the supplied application identifier. + * + * @param appId application identifier + * @return application descriptor + */ + Application getApplication(ApplicationId appId); + + /** + * Return the application state. + * + * @param appId application identifier + * @return application state + */ + ApplicationState getState(ApplicationId appId); + + /** + * Returns the permissions currently granted to the applications. + * + * @param appId application identifier + * @return set of granted permissions + */ + Set getPermissions(ApplicationId appId); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationState.java b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationState.java new file mode 100644 index 00000000..c480a0c7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationState.java @@ -0,0 +1,33 @@ +/* + * 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.app; + +/** + * Representation of an application state. + */ +public enum ApplicationState { + + /** + * Indicates that application has been installed, but is not running. + */ + INSTALLED, + + /** + * Indicates that application is active. + */ + ACTIVE + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationStore.java new file mode 100644 index 00000000..b3cdc43e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationStore.java @@ -0,0 +1,108 @@ +/* + * 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.app; + +import org.onosproject.core.Application; +import org.onosproject.core.ApplicationId; +import org.onosproject.security.Permission; +import org.onosproject.store.Store; + +import java.io.InputStream; +import java.util.Set; + +/** + * Service for managing network control applications. + */ +public interface ApplicationStore extends Store { + + /** + * Returns the set of all installed applications. + * + * @return set of installed apps + */ + Set getApplications(); + + /** + * Returns the registered id of the application with the given name. + * + * @param name application name + * @return registered application id + */ + ApplicationId getId(String name); + + /** + * Returns the application with the supplied application identifier. + * + * @param appId application identifier + * @return application descriptor + */ + Application getApplication(ApplicationId appId); + + /** + * Returns the current application state. + * + * @param appId application identifier + * @return application state + */ + ApplicationState getState(ApplicationId appId); + + /** + * Creates the application from the specified application descriptor + * input stream. + * + * @param appDescStream application archive input stream + * @return application descriptor + */ + Application create(InputStream appDescStream); + + /** + * Removes the specified application. + * + * @param appId application identifier + */ + void remove(ApplicationId appId); + + /** + * Mark the application as actived. + * + * @param appId application identifier + */ + void activate(ApplicationId appId); + + /** + * Mark the application as deactivated. + * + * @param appId application identifier + */ + void deactivate(ApplicationId appId); + + /** + * Returns the permissions granted to the applications. + * + * @param appId application identifier + * @return set of granted permissions + */ + Set getPermissions(ApplicationId appId); + + /** + * Updates the permissions granted to the applications. + * + * @param appId application identifier + * @param permissions set of granted permissions + */ + void setPermissions(ApplicationId appId, Set permissions); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationStoreDelegate.java new file mode 100644 index 00000000..f339e685 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/app/ApplicationStoreDelegate.java @@ -0,0 +1,24 @@ +/* + * 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.app; + +import org.onosproject.store.StoreDelegate; + +/** + * Application store delegate abstraction. + */ +public interface ApplicationStoreDelegate extends StoreDelegate { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/app/DefaultApplicationDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/app/DefaultApplicationDescription.java new file mode 100644 index 00000000..710d0f9c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/app/DefaultApplicationDescription.java @@ -0,0 +1,125 @@ +/* + * 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.app; + +import org.onosproject.core.ApplicationRole; +import org.onosproject.core.Version; +import org.onosproject.security.Permission; + +import java.net.URI; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default implementation of network control/management application descriptor. + */ +public class DefaultApplicationDescription implements ApplicationDescription { + + private final String name; + private final Version version; + private final String description; + private final String origin; + private final ApplicationRole role; + private final Set permissions; + private final Optional featuresRepo; + private final List features; + + /** + * Creates a new application descriptor using the supplied data. + * + * @param name application name + * @param version application version + * @param description application description + * @param origin origin company + * @param role application role + * @param permissions requested permissions + * @param featuresRepo optional features repo URI + * @param features application features + */ + public DefaultApplicationDescription(String name, Version version, + String description, String origin, + ApplicationRole role, Set permissions, + URI featuresRepo, List features) { + this.name = checkNotNull(name, "Name cannot be null"); + this.version = checkNotNull(version, "Version cannot be null"); + this.description = checkNotNull(description, "Description cannot be null"); + this.origin = checkNotNull(origin, "Origin cannot be null"); + this.role = checkNotNull(role, "Role cannot be null"); + this.permissions = checkNotNull(permissions, "Permissions cannot be null"); + this.featuresRepo = Optional.ofNullable(featuresRepo); + this.features = checkNotNull(features, "Features cannot be null"); + checkArgument(!features.isEmpty(), "There must be at least one feature"); + } + + @Override + public String name() { + return name; + } + + @Override + public Version version() { + return version; + } + + @Override + public String description() { + return description; + } + + @Override + public String origin() { + return origin; + } + + @Override + public ApplicationRole role() { + return role; + } + + @Override + public Set permissions() { + return permissions; + } + + @Override + public Optional featuresRepo() { + return featuresRepo; + } + + @Override + public List features() { + return features; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("name", name) + .add("version", version) + .add("description", description) + .add("origin", origin) + .add("role", role) + .add("permissions", permissions) + .add("featuresRepo", featuresRepo) + .add("features", features) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/app/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/app/package-info.java new file mode 100644 index 00000000..f8e5465d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/app/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. + */ + +/** + * Set of abstractions for managing network control applications. + */ +package org.onosproject.app; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigEvent.java new file mode 100644 index 00000000..0f5a2ee5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigEvent.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; + +import org.onosproject.event.AbstractEvent; + +/** + * Describes a component configuration event. + */ +public class ComponentConfigEvent extends AbstractEvent { + + private final String name; + private final String value; + + public enum Type { + /** + * Signifies that a configuration property has set. + */ + PROPERTY_SET, + + /** + * Signifies that a configuration property has been unset. + */ + PROPERTY_UNSET + } + + /** + * Creates an event of a given type and for the specified app and the + * current time. + * + * @param type config property event type + * @param componentName component name event subject + * @param name config property name + * @param value config property value + */ + public ComponentConfigEvent(Type type, String componentName, + String name, String value) { + super(type, componentName); + this.name = name; + this.value = value; + } + + /** + * Returns the property name. + * + * @return property name + */ + public String name() { + return name; + } + + /** + * Returns the property value as a string. + * + * @return string value + */ + public String value() { + return value; + } + +} 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 new file mode 100644 index 00000000..a311002f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigService.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; + +import java.util.Set; + +/** + * Service for tracking system-wide configurations for various software components. + */ +public interface ComponentConfigService { + + /** + * Returns names of all components that have registered their + * configuration properties. + * + * @return set of component names + */ + Set getComponentNames(); + + /** + * Registers configuration properties for the specified component. + * + * @param componentClass class of configurable component + */ + void registerProperties(Class componentClass); + + /** + * Unregisters configuration properties for the specified component. + * + * @param componentClass class of configurable component + * @param clear true indicates any settings should be cleared + */ + void unregisterProperties(Class componentClass, boolean clear); + + /** + * Returns configuration properties of the named components. + * + * @param componentName component name + * @return set of configuration properties + */ + Set getProperties(String componentName); + + /** + * Sets the value of the specified configuration property. + * + * @param componentName component name + * @param name property name + * @param value new property value + */ + void setProperty(String componentName, String name, String value); + + /** + * Clears the value of the specified configuration property thus making + * the property take on its default value. + * + * @param componentName component name + * @param name property name + */ + void unsetProperty(String componentName, String name); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStore.java new file mode 100644 index 00000000..05f58a4c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStore.java @@ -0,0 +1,45 @@ +/* + * 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; + +import org.onosproject.store.Store; + +/** + * Service for storing and distributing system-wide configurations for various + * software components. + */ +public interface ComponentConfigStore + extends Store { + + /** + * Sets the value of the specified configuration property. + * + * @param componentName component name + * @param name property name + * @param value new property value + */ + void setProperty(String componentName, String name, String value); + + /** + * Clears the value of the specified configuration property thus making + * the property take on its default value. + * + * @param componentName component name + * @param name property name + */ + void unsetProperty(String componentName, String name); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStoreDelegate.java new file mode 100644 index 00000000..da262789 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ComponentConfigStoreDelegate.java @@ -0,0 +1,24 @@ +/* + * 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; + +import org.onosproject.store.StoreDelegate; + +/** + * Configuration property store delegate abstraction. + */ +public interface ComponentConfigStoreDelegate extends StoreDelegate { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ConfigProperty.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ConfigProperty.java new file mode 100644 index 00000000..36cd22b5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/ConfigProperty.java @@ -0,0 +1,279 @@ +/* + * 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; + +import com.google.common.base.MoreObjects; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +/** + * Component configuration property. + */ +public final class ConfigProperty { + + private final String name; + private final Type type; + private final String value; + private final String defaultValue; + private final String description; + private final boolean isSet; + + /** + * Representation of the type of property value. + */ + public enum Type { + /** + * Indicates the value is a string. + */ + STRING, + + /** + * Indicates the value is an integer. + */ + INTEGER, + + /** + * Indicates the value is a long. + */ + LONG, + + /** + * Indicates the value is a float. + */ + FLOAT, + + /** + * Indicates the value is a double. + */ + DOUBLE, + + /** + * Indicates the value is a boolean. + */ + BOOLEAN + } + + /** + * Creates a new configuration property with its default value. + * + * @param name property name + * @param type value type + * @param defaultValue default value as a string + * @param description property description + * @return newly defined property + */ + public static ConfigProperty defineProperty(String name, Type type, + String defaultValue, + String description) { + return new ConfigProperty(name, type, description, defaultValue, defaultValue, false); + } + + /** + * Creates a new configuration property as a copy of an existing one, but + * with a new value. + * + * @param property property to be changed + * @param newValue new value as a string + * @return newly updated property + */ + public static ConfigProperty setProperty(ConfigProperty property, String newValue) { + return new ConfigProperty(property.name, property.type, property.description, + property.defaultValue, newValue, true); + } + + /** + * Creates a new configuration property as a copy of an existing one, but + * without a specific value, thus making it take its default value. + * + * @param property property to be reset + * @return newly reset property + */ + public static ConfigProperty resetProperty(ConfigProperty property) { + return new ConfigProperty(property.name, property.type, property.description, + property.defaultValue, property.defaultValue, false); + } + + /** + * Creates a new configuration property with its default value. + * + * @param name property name + * @param type value type + * @param defaultValue default value as a string + * @param description property description + * @param value property value + * @param isSet indicates whether the property is set or not + */ + private ConfigProperty(String name, Type type, String description, + String defaultValue, String value, boolean isSet) { + this.name = checkNotNull(name, "Property name cannot be null"); + this.type = checkNotNull(type, "Property type cannot be null"); + this.description = checkNotNull(description, "Property description cannot be null"); + this.defaultValue = defaultValue; + this.value = value; + this.isSet = isSet; + } + + /** + * Returns the property name. + * + * @return property name + */ + public String name() { + return name; + } + + /** + * Returns the property type. + * + * @return property type + */ + public Type type() { + return type; + } + + /** + * Returns the property description. + * + * @return string value + */ + public String description() { + return description; + } + + /** + * Returns the property default value as a string. + * + * @return string default value + */ + public String defaultValue() { + return defaultValue; + } + + /** + * Returns the property value as a string. + * + * @return string value + */ + public String value() { + return value; + } + + /** + * Indicates whether the property is set or whether it assumes its + * default value. + * + * @return true if the property is set + */ + public boolean isSet() { + return isSet; + } + + /** + * Returns the property value as a string. + * + * @return string value + */ + public String asString() { + return value; + } + + /** + * Returns the property value as an integer. + * + * @return integer value + */ + public int asInteger() { + checkState(type == Type.INTEGER, "Value is not an integer"); + return Integer.parseInt(value); + } + + /** + * Returns the property value as a long. + * + * @return long value + */ + public long asLong() { + checkState(type == Type.INTEGER || type == Type.LONG, "Value is not a long or integer"); + return Long.parseLong(value); + } + + /** + * Returns the property value as a float. + * + * @return float value + */ + public float asFloat() { + checkState(type == Type.FLOAT, "Value is not a float"); + return Float.parseFloat(value); + } + + /** + * Returns the property value as a double. + * + * @return double value + */ + public double asDouble() { + checkState(type == Type.FLOAT || type == Type.DOUBLE, "Value is not a float or double"); + return Double.parseDouble(value); + } + + /** + * Returns the property value as a boolean. + * + * @return string value + */ + public boolean asBoolean() { + checkState(type == Type.BOOLEAN, "Value is not a boolean"); + return Boolean.parseBoolean(value); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + /** + * {@inheritDoc} + * + * Equality is considered only on the basis of property name. + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ConfigProperty) { + final ConfigProperty other = (ConfigProperty) obj; + return Objects.equals(this.name, other.name); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("name", name) + .add("type", type) + .add("value", value) + .add("defaultValue", defaultValue) + .add("description", description) + .add("isSet", isSet) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/package-info.java new file mode 100644 index 00000000..99fd5be4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cfg/package-info.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +/** + * Set of abstractions for centrally managing component configurations. + * Configuration properties are registered for a component resource which is + * auto-generated during the build process based on information specified in + * the @Property annotations. This provides an overall inventory of all + * supported component configurations. + */ +package org.onosproject.cfg; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterAdminService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterAdminService.java new file mode 100644 index 00000000..5f2b5fff --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterAdminService.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014-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.cluster; + +import org.onlab.packet.IpAddress; + +import java.util.Set; + +/** + * Service for administering the cluster node membership. + */ +public interface ClusterAdminService { + + /** + * Forms cluster configuration based on the specified set of node + * information.  This method resets and restarts the controller + * instance. + * + * @param nodes set of nodes that form the cluster + * @param ipPrefix IP address prefix, e.g. 10.0.1.* + */ + void formCluster(Set nodes, String ipPrefix); + + /** + * Adds a new controller node to the cluster. + * + * @param nodeId controller node identifier + * @param ip node IP listen address + * @param tcpPort tcp listen port + * @return newly added node + */ + ControllerNode addNode(NodeId nodeId, IpAddress ip, int tcpPort); + + /** + * Removes the specified node from the cluster node list. + * + * @param nodeId controller node identifier + */ + void removeNode(NodeId nodeId); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterDefinitionService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterDefinitionService.java new file mode 100644 index 00000000..dbe5f71c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterDefinitionService.java @@ -0,0 +1,32 @@ +package org.onosproject.cluster; + +import java.util.Set; + +/** + * Service for obtaining the static definition of a controller cluster. + */ +public interface ClusterDefinitionService { + + /** + * Returns the local controller node. + * @return local controller node + */ + ControllerNode localNode(); + + /** + * Returns the set of seed nodes that should be used for discovering other members + * of the cluster. + * @return set of seed controller nodes + */ + Set seedNodes(); + + /** + * Forms cluster configuration based on the specified set of node + * information. Assumes subsequent restart for the new configuration to + * take hold. + * + * @param nodes set of nodes that form the cluster + * @param ipPrefix IP address prefix, e.g. 10.0.1.* + */ + void formCluster(Set nodes, String ipPrefix); +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterEvent.java new file mode 100644 index 00000000..7bdc1d7d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterEvent.java @@ -0,0 +1,72 @@ +/* + * Copyright 2014 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.cluster; + +import org.onosproject.event.AbstractEvent; + +/** + * Describes cluster-related event. + */ +public class ClusterEvent extends AbstractEvent { + + /** + * Type of cluster-related events. + */ + public enum Type { + /** + * Signifies that a new cluster instance has been administratively added. + */ + INSTANCE_ADDED, + + /** + * Signifies that a cluster instance has been administratively removed. + */ + INSTANCE_REMOVED, + + /** + * Signifies that a cluster instance became active. + */ + INSTANCE_ACTIVATED, + + /** + * Signifies that a cluster instance became inactive. + */ + INSTANCE_DEACTIVATED + } + + /** + * Creates an event of a given type and for the specified instance and the + * current time. + * + * @param type cluster event type + * @param instance cluster device subject + */ + public ClusterEvent(Type type, ControllerNode instance) { + super(type, instance); + } + + /** + * Creates an event of a given type and for the specified device and time. + * + * @param type device event type + * @param instance event device subject + * @param time occurrence time + */ + public ClusterEvent(Type type, ControllerNode instance, long time) { + super(type, instance, time); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterEventListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterEventListener.java new file mode 100644 index 00000000..79ff06ec --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterEventListener.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.cluster; + +import org.onosproject.event.EventListener; + +/** + * Entity capable of receiving device cluster-related events. + */ +public interface ClusterEventListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterService.java new file mode 100644 index 00000000..015a6482 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterService.java @@ -0,0 +1,68 @@ +/* + * Copyright 2014-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.cluster; + +import java.util.Set; + +import org.joda.time.DateTime; +import org.onosproject.event.ListenerService; + +/** + * Service for obtaining information about the individual nodes within + * the controller cluster. + */ +public interface ClusterService + extends ListenerService { + + /** + * Returns the local controller node. + * + * @return local controller node + */ + ControllerNode getLocalNode(); + + /** + * Returns the set of current cluster members. + * + * @return set of cluster members + */ + Set getNodes(); + + /** + * Returns the specified controller node. + * + * @param nodeId controller node identifier + * @return controller node + */ + ControllerNode getNode(NodeId nodeId); + + /** + * Returns the availability state of the specified controller node. + * + * @param nodeId controller node identifier + * @return availability state + */ + ControllerNode.State getState(NodeId nodeId); + + /** + * Returns the system time when the availability state was last updated. + * + * @param nodeId controller node identifier + * @return system time when the availability state was last updated. + */ + DateTime getLastUpdated(NodeId nodeId); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterStore.java new file mode 100644 index 00000000..0481d510 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterStore.java @@ -0,0 +1,84 @@ +/* + * Copyright 2014-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.cluster; + +import org.joda.time.DateTime; +import org.onlab.packet.IpAddress; +import org.onosproject.store.Store; + +import java.util.Set; + +/** + * Manages inventory of controller cluster nodes; not intended for direct use. + */ +public interface ClusterStore extends Store { + + /** + * Returns the local controller node. + * + * @return local controller instance + */ + ControllerNode getLocalNode(); + + /** + * Returns the set of current cluster members. + * + * @return set of cluster members + */ + Set getNodes(); + + /** + * Returns the specified controller node. + * + * @param nodeId controller instance identifier + * @return controller instance + */ + ControllerNode getNode(NodeId nodeId); + + /** + * Returns the availability state of the specified controller node. + * + * @param nodeId controller instance identifier + * @return availability state + */ + ControllerNode.State getState(NodeId nodeId); + + /** + * Returns the system when the availability state was last updated. + * + * @param nodeId controller node identifier + * @return system time when the availability state was last updated. + */ + DateTime getLastUpdated(NodeId nodeId); + + /** + * Adds a new controller node to the cluster. + * + * @param nodeId controller node identifier + * @param ip node IP listen address + * @param tcpPort tcp listen port + * @return newly added node + */ + ControllerNode addNode(NodeId nodeId, IpAddress ip, int tcpPort); + + /** + * Removes the specified node from the inventory of cluster nodes. + * + * @param nodeId controller instance identifier + */ + void removeNode(NodeId nodeId); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterStoreDelegate.java new file mode 100644 index 00000000..50d44305 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ClusterStoreDelegate.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.cluster; + +import org.onosproject.store.StoreDelegate; + +/** + * Cluster store delegate abstraction. + */ +public interface ClusterStoreDelegate extends StoreDelegate { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ControllerNode.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ControllerNode.java new file mode 100644 index 00000000..3cfc9367 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ControllerNode.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014 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.cluster; + +import org.onlab.packet.IpAddress; + +/** + * Represents a controller instance as a member in a cluster. + */ +public interface ControllerNode { + + /** Represents the operational state of the instance. */ + public enum State { + /** + * Signifies that the instance is active and operating normally. + */ + ACTIVE, + + /** + * Signifies that the instance is inactive, which means either down or + * up, but not operational. + */ + INACTIVE + } + + /** + * Returns the instance identifier. + * + * @return instance identifier + */ + NodeId id(); + + /** + * Returns the IP address of the controller instance. + * + * @return IP address + */ + IpAddress ip(); + + + /** + * Returns the TCP port on which the node listens for connections. + * + * @return TCP port + */ + int tcpPort(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ControllerNodeToNodeId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ControllerNodeToNodeId.java new file mode 100644 index 00000000..4cde8b29 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/ControllerNodeToNodeId.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014 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.cluster; + +import com.google.common.base.Function; + +/** + * Function to convert ControllerNode to NodeId. + */ +public final class ControllerNodeToNodeId + implements Function { + + private static final ControllerNodeToNodeId INSTANCE = new ControllerNodeToNodeId(); + + @Override + public NodeId apply(ControllerNode input) { + if (input == null) { + return null; + } else { + return input.id(); + } + } + + /** + * Returns a Function to convert ControllerNode to NodeId. + * + * @return ControllerNodeToNodeId instance. + */ + public static ControllerNodeToNodeId toNodeId() { + return INSTANCE; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/DefaultControllerNode.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/DefaultControllerNode.java new file mode 100644 index 00000000..5f3e0e19 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/DefaultControllerNode.java @@ -0,0 +1,103 @@ +/* + * Copyright 2014-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.cluster; + +import org.onlab.packet.IpAddress; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Default implementation of a controller instance descriptor. + */ +public class DefaultControllerNode implements ControllerNode { + + public static final int DEFAULT_PORT = 9876; + + private final NodeId id; + private final IpAddress ip; + private final int tcpPort; + + // For serialization + private DefaultControllerNode() { + this.id = null; + this.ip = null; + this.tcpPort = 0; + } + + /** + * Creates a new instance with the specified id and IP address. + * + * @param id instance identifier + * @param ip instance IP address + */ + public DefaultControllerNode(NodeId id, IpAddress ip) { + this(id, ip, DEFAULT_PORT); + } + + /** + * Creates a new instance with the specified id and IP address and TCP port. + * + * @param id instance identifier + * @param ip instance IP address + * @param tcpPort TCP port + */ + public DefaultControllerNode(NodeId id, IpAddress ip, int tcpPort) { + this.id = id; + this.ip = ip; + this.tcpPort = tcpPort; + } + + @Override + public NodeId id() { + return id; + } + + @Override + public IpAddress ip() { + return ip; + } + + @Override + public int tcpPort() { + return tcpPort; + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o instanceof DefaultControllerNode) { + DefaultControllerNode that = (DefaultControllerNode) o; + return Objects.equals(this.id, that.id); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this).add("id", id) + .add("ip", ip).add("tcpPort", tcpPort).toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/Leadership.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/Leadership.java new file mode 100644 index 00000000..113e19cb --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/Leadership.java @@ -0,0 +1,164 @@ +/* + * Copyright 2014-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.cluster; + +import java.util.Objects; +import java.util.List; +import java.util.Optional; + +import org.joda.time.DateTime; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; + +/** + * Abstract leadership concept. The information carried by this construct + * include the topic of contention, the {@link NodeId}s of Nodes that could + * become leader for the topic, the epoch when the term for a given leader + * began, and the system time when the term began. Note: + *
    + *
  • The list of NodeIds may include the current leader at index 0, and the + * rest in decreasing preference order.
  • + *
  • The epoch is the logical age of a Leadership construct, and should be + * used for comparing two Leaderships, but only of the same topic.
  • + *
  • The leader may be null if its accuracy can't be guaranteed. This applies + * to CANDIDATES_CHANGED events and candidate board contents.
  • + *
+ */ +public class Leadership { + + private final String topic; + private final Optional leader; + private final List candidates; + private final long epoch; + private final long electedTime; + + public Leadership(String topic, NodeId leader, long epoch, long electedTime) { + this.topic = topic; + this.leader = Optional.of(leader); + this.candidates = ImmutableList.of(leader); + this.epoch = epoch; + this.electedTime = electedTime; + } + + public Leadership(String topic, NodeId leader, List candidates, + long epoch, long electedTime) { + this.topic = topic; + this.leader = Optional.of(leader); + this.candidates = ImmutableList.copyOf(candidates); + this.epoch = epoch; + this.electedTime = electedTime; + } + + public Leadership(String topic, List candidates, + long epoch, long electedTime) { + this.topic = topic; + this.leader = Optional.empty(); + this.candidates = ImmutableList.copyOf(candidates); + this.epoch = epoch; + this.electedTime = electedTime; + } + + /** + * The topic for which this leadership applies. + * + * @return leadership topic. + */ + public String topic() { + return topic; + } + + /** + * The nodeId of leader for this topic. + * + * @return leader node. + */ + // This will return Optional in the future. + public NodeId leader() { + return leader.orElse(null); + } + + /** + * Returns an preference-ordered list of nodes that are in the leadership + * race for this topic. + * + * @return a list of NodeIds in priority-order, or an empty list. + */ + public List candidates() { + return candidates; + } + + /** + * The epoch when the leadership was assumed. + *

+ * Comparing epochs is only appropriate for leadership events for the same + * topic. The system guarantees that for any given topic the epoch for a new + * term is higher (not necessarily by 1) than the epoch for any previous + * term. + * + * @return leadership epoch + */ + public long epoch() { + return epoch; + } + + /** + * The system time when the term started. + *

+ * The elected time is initially set on the node coordinating + * the leader election using its local system time. Due to possible + * clock skew, relying on this value for determining event ordering + * is discouraged. Epoch is more appropriate for determining + * event ordering. + * + * @return elected time. + */ + public long electedTime() { + return electedTime; + } + + @Override + public int hashCode() { + return Objects.hash(topic, leader, candidates, epoch, electedTime); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Leadership) { + final Leadership other = (Leadership) obj; + return Objects.equals(this.topic, other.topic) && + Objects.equals(this.leader, other.leader) && + Objects.equals(this.candidates, other.candidates) && + Objects.equals(this.epoch, other.epoch) && + Objects.equals(this.electedTime, other.electedTime); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this.getClass()) + .add("topic", topic) + .add("leader", leader) + .add("candidates", candidates) + .add("epoch", epoch) + .add("electedTime", new DateTime(electedTime)) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/LeadershipEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/LeadershipEvent.java new file mode 100644 index 00000000..faf6dd45 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/LeadershipEvent.java @@ -0,0 +1,107 @@ +/* + * Copyright 2014-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.cluster; + +import java.util.Objects; + +import org.onosproject.event.AbstractEvent; + +import com.google.common.base.MoreObjects; + +/** + * Describes leadership-related event. + */ +public class LeadershipEvent extends AbstractEvent { + + /** + * Type of leadership-related events. + */ + public enum Type { + /** + * Signifies that the leader has been elected. The event subject is the + * new leader. + */ + LEADER_ELECTED, + + /** + * Signifies that the leader has been re-elected. The event subject is the + * leader. + */ + LEADER_REELECTED, + + /** + * Signifies that the leader has been booted and lost leadership. The + * event subject is the former leader. + */ + LEADER_BOOTED, + + /** + * Signifies that the list of candidates for leadership for a topic has + * changed. This event does not guarantee accurate leader information. + */ + CANDIDATES_CHANGED + } + + /** + * Creates an event of a given type and for the specified instance and the + * current time. + * + * @param type leadership event type + * @param leadership event subject + */ + public LeadershipEvent(Type type, Leadership leadership) { + super(type, leadership); + } + + /** + * Creates an event of a given type and for the specified subject and time. + * + * @param type leadership event type + * @param leadership event subject + * @param time occurrence time + */ + public LeadershipEvent(Type type, Leadership leadership, long time) { + super(type, leadership, time); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subject(), time()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof LeadershipEvent) { + final LeadershipEvent other = (LeadershipEvent) obj; + return Objects.equals(this.type(), other.type()) && + Objects.equals(this.subject(), other.subject()) && + Objects.equals(this.time(), other.time()); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this.getClass()) + .add("type", type()) + .add("subject", subject()) + .add("time", time()) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/LeadershipEventListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/LeadershipEventListener.java new file mode 100644 index 00000000..53d84b1b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/LeadershipEventListener.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.cluster; + +import org.onosproject.event.EventListener; + +/** + * Entity capable of receiving device leadership-related events. + */ +public interface LeadershipEventListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/LeadershipService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/LeadershipService.java new file mode 100644 index 00000000..7d1f6079 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/LeadershipService.java @@ -0,0 +1,124 @@ +/* + * Copyright 2014-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.cluster; + +import org.onosproject.event.ListenerService; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; + +/** + * Service for leader election. + * Leadership contests are organized around topics. A instance can join the + * leadership race for a topic or withdraw from a race it has previously joined. + * Listeners can be added to receive notifications asynchronously for various + * leadership contests. + */ +public interface LeadershipService + extends ListenerService { + + /** + * Returns the current leader for the topic. + * + * @param path topic + * @return nodeId of the leader, null if so such topic exists. + */ + NodeId getLeader(String path); + + /** + * Returns the current leadership info for the topic. + * + * @param path topic + * @return leadership info or null if so such topic exists. + */ + Leadership getLeadership(String path); + + /** + * Returns the set of topics owned by the specified node. + * + * @param nodeId node Id. + * @return set of topics for which this node is the current leader. + */ + Set ownedTopics(NodeId nodeId); + + /** + * Joins the leadership contest. + * + * @param path topic for which this controller node wishes to be a leader + * @return {@code Leadership} future + */ + CompletableFuture runForLeadership(String path); + + /** + * Withdraws from a leadership contest. + * + * @param path topic for which this controller node no longer wishes to be a leader + * @return future that is successfully completed when withdraw is done + */ + CompletableFuture withdraw(String path); + + /** + * If the local nodeId is the leader for specified topic, this method causes it to + * step down temporarily from leadership. + *

+ * The node will continue to be in contention for leadership and can + * potentially become the leader again if and when it becomes the highest + * priority candidate + *

+ * If the local nodeId is not the leader, this method will make no changes and + * simply return false. + * + * @param path topic for which this controller node should give up leadership + * @return true if this node stepped down from leadership, false otherwise + */ + boolean stepdown(String path); + + /** + * Moves the specified nodeId to the top of the candidates list for the topic. + *

+ * If the node is not a candidate for this topic, this method will be a noop. + * + * @param path leadership topic + * @param nodeId nodeId to make the top candidate + * @return true if nodeId is now the top candidate, false otherwise + */ + boolean makeTopCandidate(String path, NodeId nodeId); + + /** + * Returns the current leader board. + * + * @return mapping from topic to leadership info. + */ + Map getLeaderBoard(); + + /** + * Returns the candidates for all known topics. + * + * @return A mapping from topics to corresponding list of candidates. + */ + Map> getCandidates(); + + /** + * Returns the candidates for a given topic. + * + * @param path topic + * @return A lists of NodeIds, which may be empty. + */ + List getCandidates(String path); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/NodeId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/NodeId.java new file mode 100644 index 00000000..68b490f2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/NodeId.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014 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.cluster; + +import java.util.Objects; + +/** + * Controller cluster identity. + */ +public class NodeId { + + private final String id; + + /** + * Creates a new cluster node identifier from the specified string. + * + * @param id string identifier + */ + public NodeId(String id) { + this.id = id; + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof NodeId) { + final NodeId other = (NodeId) obj; + return Objects.equals(this.id, other.id); + } + return false; + } + + @Override + public String toString() { + return id; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/RoleInfo.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/RoleInfo.java new file mode 100644 index 00000000..081a6ba2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/RoleInfo.java @@ -0,0 +1,80 @@ +/* + * Copyright 2014-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.cluster; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; + +/** + * An immutable container for role information for a device, + * within the current cluster. Role attributes include current + * master and a preference-ordered list of backup nodes. + */ +public class RoleInfo { + private final Optional master; + private final List backups; + + public RoleInfo(NodeId master, List backups) { + this.master = Optional.ofNullable(master); + this.backups = ImmutableList.copyOf(backups); + } + + public RoleInfo() { + this.master = Optional.empty(); + this.backups = ImmutableList.of(); + } + + // This will return a Optional in the future. + public NodeId master() { + return master.orElseGet(() -> null); + } + + public List backups() { + return backups; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (!(other instanceof RoleInfo)) { + return false; + } + RoleInfo that = (RoleInfo) other; + + return Objects.equals(this.master, that.master) + && Objects.equals(this.backups, that.backups); + } + + @Override + public int hashCode() { + return Objects.hash(master, backups); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this.getClass()) + .add("master", master.orElseGet(() -> null)) + .add("backups", backups) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/package-info.java new file mode 100644 index 00000000..d5ae40c2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/cluster/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Set of abstractions for dealing with controller cluster related topics. + */ +package org.onosproject.cluster; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/codec/CodecContext.java b/framework/src/onos/core/api/src/main/java/org/onosproject/codec/CodecContext.java new file mode 100644 index 00000000..272c3e90 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/codec/CodecContext.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014 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; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Context for codecs to use while encoding/decoding. + */ +public interface CodecContext { + + /** + * Returns the JSON object mapper. + * + * @return object mapper + */ + ObjectMapper mapper(); + + /** + * Returns the JSON codec for the specified entity class. + * + * @param entityClass entity class + * @param entity type + * @return JSON codec; null if no codec available for the class + */ + JsonCodec codec(Class entityClass); + + /** + * Returns reference to the specified service implementation. + * + * @param serviceClass service class + * @param service type + * @return JSON codec; null if no codec available for the class + */ + T getService(Class serviceClass); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/codec/CodecService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/codec/CodecService.java new file mode 100644 index 00000000..2705569d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/codec/CodecService.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014 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; + +import java.util.Set; + +/** + * Service for registering and retrieving JSON codecs for various entities. + */ +public interface CodecService { + + /** + * Returns the set of classes with currently registered codecs. + * + * @return set of entity classes + */ + Set> getCodecs(); + + /** + * Returns the JSON codec for the specified entity class. + * + * @param entityClass entity class + * @param entity type + * @return JSON codec; null if no codec available for the class + */ + JsonCodec getCodec(Class entityClass); + + /** + * Registers the specified JSON codec for the given entity class. + * + * @param entityClass entity class + * @param codec JSON codec + * @param entity type + */ + void registerCodec(Class entityClass, JsonCodec codec); + + /** + * Unregisters the JSON codec for the specified entity class. + * + * @param entityClass entity class + */ + void unregisterCodec(Class entityClass); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/codec/JsonCodec.java b/framework/src/onos/core/api/src/main/java/org/onosproject/codec/JsonCodec.java new file mode 100644 index 00000000..6df8f117 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/codec/JsonCodec.java @@ -0,0 +1,115 @@ +/* + * Copyright 2014 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; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import java.util.ArrayList; +import java.util.List; + +/** + * Abstraction of a codec capable for encoding/decoding arbitrary objects to/from JSON. + */ +public abstract class JsonCodec { + + /** + * Encodes the specified entity into JSON. + * + * @param entity entity to encode + * @param context encoding context + * @return JSON node + * @throws java.lang.UnsupportedOperationException if the codec does not + * support encode operations + */ + public ObjectNode encode(T entity, CodecContext context) { + throw new UnsupportedOperationException("encode() not supported"); + } + + /** + * Decodes the specified entity from JSON. + * + * @param json JSON to decode + * @param context decoding context + * @return decoded entity + * @throws java.lang.UnsupportedOperationException if the codec does not + * support decode operations + */ + public T decode(ObjectNode json, CodecContext context) { + throw new UnsupportedOperationException("decode() not supported"); + } + + /** + * Encodes the collection of the specified entities. + * + * @param entities collection of entities to encode + * @param context encoding context + * @return JSON array + * @throws java.lang.UnsupportedOperationException if the codec does not + * support encode operations + */ + public ArrayNode encode(Iterable entities, CodecContext context) { + ArrayNode result = context.mapper().createArrayNode(); + for (T entity : entities) { + result.add(encode(entity, context)); + } + return result; + } + + /** + * Decodes the specified JSON array into a collection of entities. + * + * @param json JSON array to decode + * @param context decoding context + * @return collection of decoded entities + * @throws java.lang.UnsupportedOperationException if the codec does not + * support decode operations + */ + public List decode(ArrayNode json, CodecContext context) { + List result = new ArrayList<>(); + for (JsonNode node : json) { + result.add(decode((ObjectNode) node, context)); + } + return result; + } + + /** + * Gets a child Object Node from a parent by name. If the child is not found + * or does nor represent an object, null is returned. + * + * @param parent parent object + * @param childName name of child to query + * @return child object if found, null if not found or if not an object + */ + protected static ObjectNode get(ObjectNode parent, String childName) { + JsonNode node = parent.path(childName); + return node.isObject() && !node.isNull() ? (ObjectNode) node : null; + } + + /** + * Gets a child Object Node from a parent by index. If the child is not found + * or does nor represent an object, null is returned. + * + * @param parent parent object + * @param childIndex index of child to query + * @return child object if found, null if not found or if not an object + */ + protected static ObjectNode get(JsonNode parent, int childIndex) { + JsonNode node = parent.path(childIndex); + return node.isObject() && !node.isNull() ? (ObjectNode) node : null; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/codec/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/codec/package-info.java new file mode 100644 index 00000000..0aa063f5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/codec/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Base JSON codec abstraction and a service for tracking various JSON codecs. + */ +package org.onosproject.codec; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/Application.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/Application.java new file mode 100644 index 00000000..fca53843 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/Application.java @@ -0,0 +1,87 @@ +/* + * 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.core; + +import org.onosproject.security.Permission; + +import java.net.URI; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * Abstraction of a network control/management application. + */ +public interface Application { + + /** + * Returns the application name id. + * + * @return application identifier + */ + ApplicationId id(); + + /** + * Returns the application version. + * + * @return application version + */ + Version version(); + + /** + * Returns description of the application. + * + * @return application description text + */ + String description(); + + /** + * Returns the name of the application origin, group or company. + * + * @return application origin + */ + String origin(); + + /** + * Returns the role of the application. + * + * @return application role + */ + ApplicationRole role(); + + /** + * Returns the permissions requested by the application. + * + * @return requested permissions + */ + Set permissions(); + + /** + * Returns the feature repository URI. Null value signifies that the + * application did not provide its own features repository. + * + * @return optional feature repo URL + */ + Optional featuresRepo(); + + /** + * Returns the list of features comprising the application. At least one + * feature must be given. + * + * @return application features + */ + List features(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/ApplicationId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/ApplicationId.java new file mode 100644 index 00000000..25bc8ce7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/ApplicationId.java @@ -0,0 +1,36 @@ +/* + * Copyright 2014 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.core; + + +/** + * Application identifier. + */ +public interface ApplicationId { + + /** + * Returns the application id. + * @return a short value + */ + short id(); + + /** + * Returns the applications supplied identifier. + * @return a string identifier + */ + String name(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/ApplicationIdStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/ApplicationIdStore.java new file mode 100644 index 00000000..f857fbdc --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/ApplicationIdStore.java @@ -0,0 +1,59 @@ +/* + * Copyright 2014-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.core; +// FIXME: Move to org.onosproject.app package + +import java.util.Set; + +/** + * Manages application IDs. + */ +public interface ApplicationIdStore { + + /** + * Returns the set of currently registered application identifiers. + * + * @return set of application ids + */ + Set getAppIds(); + + /** + * Returns an existing application id from a given id. + * + * @param id the short value of the id + * @return an application id; null if no such app registered + */ + ApplicationId getAppId(Short id); + + /** + * Returns registered application id from the given name. + * + * @param name application name + * @return an application id; null if no such app registered + */ + ApplicationId getAppId(String name); + + /** + * Registers a new application by its name, which is expected + * to follow the reverse DNS convention, e.g. + * {@code org.flying.circus.app} + * + * @param identifier string identifier + * @return the application id + */ + ApplicationId registerApplication(String identifier); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/ApplicationRole.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/ApplicationRole.java new file mode 100644 index 00000000..5fcb80ba --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/ApplicationRole.java @@ -0,0 +1,38 @@ +/* + * 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.core; + +public enum ApplicationRole { + /** + * Indicates that an application has an ADMIN role. + */ + ADMIN, + + /** + * Indicates that an application has a USER role. + */ + USER, + + /** + * Indicates that an application role has not been specified. + */ + UNSPECIFIED, + + /** + * More useful roles may be defined. + */ +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/CoreService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/CoreService.java new file mode 100644 index 00000000..3dfc6b26 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/CoreService.java @@ -0,0 +1,83 @@ +/* + * Copyright 2014-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.core; + +import org.onosproject.net.provider.ProviderId; + +import java.util.Set; + +/** + * Service for interacting with the core system of the controller. + */ +public interface CoreService { + + /** + * Name of the core "application". + */ + static final String CORE_APP_NAME = "org.onosproject.core"; + + /** + * Identifier of the core "provider". + */ + static final ProviderId CORE_PROVIDER_ID = new ProviderId("core", CORE_APP_NAME); + + /** + * Returns the product version. + * + * @return product version + */ + Version version(); + + /** + * Returns the set of currently registered application identifiers. + * + * @return set of application ids + */ + Set getAppIds(); + + /** + * Returns an existing application id from a given id. + * @param id the short value of the id + * @return an application id + */ + ApplicationId getAppId(Short id); + + /** + * Returns an existing application id from a given id. + * @param name the name portion of the ID to look up + * @return an application id + */ + ApplicationId getAppId(String name); + + /** + * Registers a new application by its name, which is expected + * to follow the reverse DNS convention, e.g. + * {@code org.flying.circus.app} + * + * @param identifier string identifier + * @return the application id + */ + ApplicationId registerApplication(String identifier); + + /** + * Returns an id generator for a given topic. + * + * @param topic topic identified + * @return the id generator + */ + IdGenerator getIdGenerator(String topic); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultApplication.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultApplication.java new file mode 100644 index 00000000..d8062ddf --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultApplication.java @@ -0,0 +1,149 @@ +/* + * 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.core; + +import org.onosproject.security.Permission; + +import java.net.URI; +import java.util.Set; +import java.util.Optional; +import java.util.List; +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default implementation of network control/management application descriptor. + */ +public class DefaultApplication implements Application { + + private final ApplicationId appId; + private final Version version; + private final String description; + private final String origin; + private final ApplicationRole role; + private final Set permissions; + private final Optional featuresRepo; + private final List features; + + /** + * Creates a new application descriptor using the supplied data. + * + * @param appId application identifier + * @param version application version + * @param description application description + * @param origin origin company + * @param role application role + * @param permissions requested permissions + * @param featuresRepo optional features repo URI + * @param features application features + */ + public DefaultApplication(ApplicationId appId, Version version, + String description, String origin, + ApplicationRole role, Set permissions, + Optional featuresRepo, List features) { + this.appId = checkNotNull(appId, "ID cannot be null"); + this.version = checkNotNull(version, "Version cannot be null"); + this.description = checkNotNull(description, "Description cannot be null"); + this.origin = checkNotNull(origin, "Origin cannot be null"); + this.role = checkNotNull(role, "Role cannot be null"); + this.permissions = checkNotNull(permissions, "Permissions cannot be null"); + this.featuresRepo = checkNotNull(featuresRepo, "Features repo cannot be null"); + this.features = checkNotNull(features, "Features cannot be null"); + checkArgument(!features.isEmpty(), "There must be at least one feature"); + } + + @Override + public ApplicationId id() { + return appId; + } + + @Override + public Version version() { + return version; + } + + @Override + public String description() { + return description; + } + + @Override + public String origin() { + return origin; + } + + @Override + public ApplicationRole role() { + return role; + } + + @Override + public Set permissions() { + return permissions; + } + + @Override + public Optional featuresRepo() { + return featuresRepo; + } + + @Override + public List features() { + return features; + } + + @Override + public int hashCode() { + return Objects.hash(appId, version, description, origin, role, permissions, + featuresRepo, features); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final DefaultApplication other = (DefaultApplication) obj; + return Objects.equals(this.appId, other.appId) && + Objects.equals(this.version, other.version) && + Objects.equals(this.description, other.description) && + Objects.equals(this.origin, other.origin) && + Objects.equals(this.role, other.role) && + Objects.equals(this.permissions, other.permissions) && + Objects.equals(this.featuresRepo, other.featuresRepo) && + Objects.equals(this.features, other.features); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("appId", appId) + .add("version", version) + .add("description", description) + .add("origin", origin) + .add("role", role) + .add("permissions", permissions) + .add("featuresRepo", featuresRepo) + .add("features", features) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultApplicationId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultApplicationId.java new file mode 100644 index 00000000..c7b5b2da --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultApplicationId.java @@ -0,0 +1,81 @@ +/* + * Copyright 2014-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.core; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Application identifier. + */ +public class DefaultApplicationId implements ApplicationId { + + private final short id; + private final String name; + + /** + * Creates a new application ID. + * + * @param id application identifier + * @param name application name + */ + public DefaultApplicationId(int id, String name) { + checkArgument(0 <= id && id <= Short.MAX_VALUE, "id is outside range"); + this.id = (short) id; + this.name = name; + } + + // Constructor for serializers. + private DefaultApplicationId() { + this.id = 0; + this.name = null; + } + + @Override + public short id() { + return id; + } + + @Override + public String name() { + return name; + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultApplicationId) { + DefaultApplicationId other = (DefaultApplicationId) obj; + return Objects.equals(this.id, other.id); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this).add("id", id).add("name", name).toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultGroupId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultGroupId.java new file mode 100644 index 00000000..9fa8d2b6 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/DefaultGroupId.java @@ -0,0 +1,66 @@ +/* + * Copyright 2014-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.core; + +import com.google.common.base.MoreObjects; + +import java.util.Objects; + +/** + * Default implementation of {@link GroupId}. + */ +public class DefaultGroupId implements GroupId { + + private final int id; + + public DefaultGroupId(int id) { + this.id = id; + } + + // Constructor for serialization + private DefaultGroupId() { + this.id = 0; + } + + @Override + public int id() { + return this.id; + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof DefaultGroupId)) { + return false; + } + final DefaultGroupId other = (DefaultGroupId) obj; + return Objects.equals(this.id, other.id); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("id", id) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/GroupId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/GroupId.java new file mode 100644 index 00000000..739fc7ff --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/GroupId.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014 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.core; + +/** + * Group identifier. + */ +public interface GroupId { + + /** + * Returns a group ID as an integer value. + * The method is not intended for use by application developers. + * Return data type may change in the future release. + * + * @return a group ID as integer value + */ + int id(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/IdBlock.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/IdBlock.java new file mode 100644 index 00000000..f4088603 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/IdBlock.java @@ -0,0 +1,102 @@ +/* + * Copyright 2014 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.core; + +import com.google.common.base.MoreObjects; + +import java.util.concurrent.atomic.AtomicLong; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * A class representing an ID space. + */ +public final class IdBlock { + private final long start; + private final long size; + + private final AtomicLong currentId; + + /** + * Constructs a new ID block with the specified size and initial value. + * + * @param start initial value of the block + * @param size size of the block + * @throws IllegalArgumentException if the size is less than or equal to 0 + */ + public IdBlock(long start, long size) { + checkArgument(size > 0, "size should be more than 0, but %s", size); + + this.start = start; + this.size = size; + + this.currentId = new AtomicLong(start); + } + + /** + * Returns the initial value. + * + * @return initial value + */ + private long getStart() { + return start; + } + + /** + * Returns the last value. + * + * @return last value + */ + private long getEnd() { + return start + size - 1; + } + + /** + * Returns the block size. + * + * @return block size + */ + public long getSize() { + return size; + } + + /** + * Returns the next ID in the block. + * + * @return next ID + * @throws UnavailableIdException if there is no available ID in the block. + */ + public long getNextId() { + final long id = currentId.getAndIncrement(); + if (id > getEnd()) { + throw new UnavailableIdException(String.format( + "used all IDs in allocated space (size: %d, end: %d, current: %d)", + size, getEnd(), id + )); + } + + return id; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("start", start) + .add("size", size) + .add("currentId", currentId) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/IdBlockStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/IdBlockStore.java new file mode 100644 index 00000000..8ed58ae7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/IdBlockStore.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014 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.core; + +/** + * Manages id blocks. + */ +public interface IdBlockStore { + + /** + * Returns a topic-unique block of ids. + * + * @param topic topic name + * @return id block + */ + IdBlock getIdBlock(String topic); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/IdGenerator.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/IdGenerator.java new file mode 100644 index 00000000..149c834b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/IdGenerator.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014 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.core; + +/** + * A generalized interface for ID generation + * + * {@link #getNewId()} generates a globally unique ID instance on + * each invocation. + */ +public interface IdGenerator { + /** + * Returns a globally unique ID instance. + * + * @return globally unique ID instance + */ + long getNewId(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/MetricsHelper.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/MetricsHelper.java new file mode 100644 index 00000000..b5be0944 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/MetricsHelper.java @@ -0,0 +1,56 @@ +/* + * Copyright 2014 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.core; + +import org.onlab.metrics.MetricsComponent; +import org.onlab.metrics.MetricsFeature; +import org.onlab.metrics.MetricsService; + +import com.codahale.metrics.Timer; + +/** + * Collection of utility methods used for providing Metrics. + */ +public interface MetricsHelper { + + /** + * Returns MetricService instance. + * + * @return MetricService instance + */ + abstract MetricsService metricsService(); + + + /** + * Creates a Timer instance with given name. + * + * @param component component name + * @param feature feature name + * @param name timer name + * @return Timer instance + */ + default Timer createTimer(String component, String feature, String name) { + final MetricsService metricsService = metricsService(); + if (metricsService != null) { + MetricsComponent c = metricsService.registerComponent(component); + MetricsFeature f = c.registerFeature(feature); + return metricsService.createTimer(c, f, name); + } + return null; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/UnavailableIdException.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/UnavailableIdException.java new file mode 100644 index 00000000..2e4af264 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/UnavailableIdException.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 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.core; + +/** + * Represents that there is no available IDs. + */ +public class UnavailableIdException extends RuntimeException { + + private static final long serialVersionUID = -2287403908433720122L; + + /** + * Constructs an exception with no message and no underlying cause. + */ + public UnavailableIdException() { + } + + /** + * Constructs an exception with the specified message. + * + * @param message the message describing the specific nature of the error + */ + public UnavailableIdException(String message) { + super(message); + } + + /** + * Constructs an exception with the specified message and the underlying cause. + * + * @param message the message describing the specific nature of the error + * @param cause the underlying cause of this error + */ + public UnavailableIdException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/Version.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/Version.java new file mode 100644 index 00000000..a5377016 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/Version.java @@ -0,0 +1,144 @@ +/* + * Copyright 2014-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.core; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Strings.isNullOrEmpty; +import static java.lang.Integer.parseInt; + +/** + * Representation of the product version. + */ +public final class Version { + + public static final String FORMAT_MINIMAL = "%d.%d"; + public static final String FORMAT_SHORT = "%d.%d.%s"; + public static final String FORMAT_LONG = "%d.%d.%s.%s"; + + private static final String NEGATIVE = "Version segment cannot be negative"; + public static final String TOO_SHORT = "Version must have at least major and minor numbers"; + + private final int major; + private final int minor; + private final String patch; + private final String build; + + private final String format; + + // Creates a new version descriptor + private Version(int major, int minor, String patch, String build) { + this.major = major; + this.minor = minor; + this.patch = patch; + this.build = build; + this.format = + isNullOrEmpty(patch) ? + String.format(FORMAT_MINIMAL, major, minor) : + (isNullOrEmpty(build) ? + String.format(FORMAT_SHORT, major, minor, patch) : + String.format(FORMAT_LONG, major, minor, patch, build)); + } + + + /** + * Creates a new version from the specified constituent numbers. + * + * @param major major version number + * @param minor minor version number + * @param patch version patch segment + * @param build optional build string + * @return version descriptor + */ + public static Version version(int major, int minor, String patch, String build) { + checkArgument(major >= 0, NEGATIVE); + checkArgument(minor >= 0, NEGATIVE); + return new Version(major, minor, patch, build); + } + + /** + * Creates a new version by parsing the specified string. + * + * @param string version string + * @return version descriptor + */ + public static Version version(String string) { + String[] fields = string.split("[.-]"); + checkArgument(fields.length >= 2, TOO_SHORT); + return new Version(parseInt(fields[0]), parseInt(fields[1]), + fields.length >= 3 ? fields[2] : null, + fields.length >= 4 ? fields[3] : null); + } + + /** + * Returns the major version number. + * + * @return major version number + */ + public int major() { + return major; + } + + /** + * Returns the minor version number. + * + * @return minor version number + */ + public int minor() { + return minor; + } + + /** + * Returns the version patch segment. + * + * @return patch number + */ + public String patch() { + return patch; + } + + /** + * Returns the version build string. + * + * @return build string + */ + public String build() { + return build; + } + + @Override + public String toString() { + return format; + } + + @Override + public int hashCode() { + return Objects.hash(format); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Version) { + final Version other = (Version) obj; + return Objects.equals(this.format, other.format); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/core/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/core/package-info.java new file mode 100644 index 00000000..3766d49f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/core/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * ONOS Core API definitions. + */ +package org.onosproject.core; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/event/AbstractEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/event/AbstractEvent.java new file mode 100644 index 00000000..67b10292 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/event/AbstractEvent.java @@ -0,0 +1,78 @@ +/* + * Copyright 2014-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.event; + +import org.joda.time.LocalDateTime; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Base event implementation. + */ +public class AbstractEvent implements Event { + + private final long time; + private final T type; + private final S subject; + + /** + * Creates an event of a given type and for the specified subject and the + * current time. + * + * @param type event type + * @param subject event subject + */ + protected AbstractEvent(T type, S subject) { + this(type, subject, System.currentTimeMillis()); + } + + /** + * Creates an event of a given type and for the specified subject and time. + * + * @param type event type + * @param subject event subject + * @param time occurrence time + */ + protected AbstractEvent(T type, S subject, long time) { + this.type = type; + this.subject = subject; + this.time = time; + } + + @Override + public long time() { + return time; + } + + @Override + public T type() { + return type; + } + + @Override + public S subject() { + return subject; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("time", new LocalDateTime(time)) + .add("type", type()) + .add("subject", subject()) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/event/AbstractListenerManager.java b/framework/src/onos/core/api/src/main/java/org/onosproject/event/AbstractListenerManager.java new file mode 100644 index 00000000..cbe7421f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/event/AbstractListenerManager.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.event; + +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; + +/** + * Basis for components which need to export listener mechanism. + */ +@Component(componentAbstract = true) +public abstract class AbstractListenerManager> + implements ListenerService { + + protected final ListenerRegistry listenerRegistry = new ListenerRegistry<>(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected EventDeliveryService eventDispatcher; + + @Override + public void addListener(L listener) { + listenerRegistry.addListener(listener); + } + + @Override + public void removeListener(L listener) { + listenerRegistry.removeListener(listener); + } + + + /** + * Safely posts the specified event to the local event dispatcher. + * If there is no event dispatcher or if the event is null, this method + * is a noop. + * + * @param event event to be posted; may be null + */ + protected void post(E event) { + if (event != null && eventDispatcher != null) { + eventDispatcher.post(event); + } + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/event/DefaultEventSinkRegistry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/event/DefaultEventSinkRegistry.java new file mode 100644 index 00000000..be6ddb61 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/event/DefaultEventSinkRegistry.java @@ -0,0 +1,62 @@ +/* + * Copyright 2014 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.event; + +import com.google.common.collect.ImmutableSet; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Base implementation of event sink registry. + */ +public class DefaultEventSinkRegistry implements EventSinkRegistry { + + private final Map, EventSink> + sinks = new ConcurrentHashMap<>(); + + @Override + public void addSink(Class eventClass, EventSink sink) { + checkNotNull(eventClass, "Event class cannot be null"); + checkNotNull(sink, "Event sink cannot be null"); + checkArgument(!sinks.containsKey(eventClass), + "Event sink already registered for %s", eventClass.getName()); + sinks.put(eventClass, sink); + } + + @Override + public void removeSink(Class eventClass) { + checkNotNull(eventClass, "Event class cannot be null"); + checkArgument(sinks.remove(eventClass) != null, + "Event sink not registered for %s", eventClass.getName()); + } + + @Override + @SuppressWarnings("unchecked") + public EventSink getSink(Class eventClass) { + checkNotNull(eventClass, "Event class cannot be null"); + return (EventSink) sinks.get(eventClass); + } + + @Override + public Set> getSinks() { + return ImmutableSet.copyOf(sinks.keySet()); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/event/Event.java b/framework/src/onos/core/api/src/main/java/org/onosproject/event/Event.java new file mode 100644 index 00000000..e7cbb60f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/event/Event.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014-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.event; + +/** + * Abstraction of an of a time-stamped event pertaining to an arbitrary subject. + */ +public interface Event { + + /** + * Returns the timestamp of when the event occurred, given in milliseconds + * since the start of epoch. + * + * @return timestamp in milliseconds + */ + long time(); + + /** + * Returns the type of the event. + * + * @return event type + */ + T type(); + + /** + * Returns the subject of the event. + * + * @return subject to which this event pertains + */ + S subject(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventDeliveryService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventDeliveryService.java new file mode 100644 index 00000000..ff268935 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventDeliveryService.java @@ -0,0 +1,38 @@ +/* + * Copyright 2014 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.event; + +/** + * Abstraction of an entity capable of accepting events to be posted and + * then dispatching them to the appropriate event sink. + */ +public interface EventDeliveryService extends EventDispatcher, EventSinkRegistry { + + /** + * Sets the number of millis that an event sink has to process an event. + * + * @param millis number of millis allowed per sink per event + */ + void setDispatchTimeLimit(long millis); + + /** + * Returns the number of millis that an event sink has to process an event. + * + * @return number of millis allowed per sink per event + */ + long getDispatchTimeLimit(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventDispatcher.java b/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventDispatcher.java new file mode 100644 index 00000000..daebd8b0 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventDispatcher.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 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.event; + +/** + * Abstraction of a mechanism capable of accepting and dispatching events to + * appropriate event sinks. Where the event sinks are obtained is unspecified. + * Similarly, whether the events are accepted and dispatched synchronously + * or asynchronously is unspecified as well. + */ +public interface EventDispatcher { + + /** + * Posts the specified event for dispatching. + * + * @param event event to be posted + */ + void post(Event event); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventFilter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventFilter.java new file mode 100644 index 00000000..3b2498f6 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventFilter.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.event; + +/** + * Entity capable of filtering events. + */ +public interface EventFilter { + + /** + * Indicates whether the specified event is of interest or not. + * Default implementation always returns true. + * + * @param event event to be inspected + * @return true if event is relevant; false otherwise + */ + default boolean isRelevant(E event) { + return true; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventListener.java new file mode 100644 index 00000000..e77369fc --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventListener.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014 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.event; + +/** + * Entity capable of receiving events. + */ +public interface EventListener extends EventFilter { + + /** + * Reacts to the specified event. + * + * @param event event to be processed + */ + void event(E event); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventSink.java b/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventSink.java new file mode 100644 index 00000000..221b3224 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventSink.java @@ -0,0 +1,36 @@ +/* + * Copyright 2014 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.event; + +/** + * Abstraction of an event sink capable of processing the specified event types. + */ +public interface EventSink { + + /** + * Processes the specified event. + * + * @param event event to be processed + */ + void process(E event); + + /** + * Handles notification that event processing time limit has been exceeded. + */ + default void onProcessLimit() { + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventSinkRegistry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventSinkRegistry.java new file mode 100644 index 00000000..bb054a30 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/event/EventSinkRegistry.java @@ -0,0 +1,60 @@ +/* + * Copyright 2014 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.event; + +import java.util.Set; + +/** + * Abstraction of an event sink registry capable of tracking sinks based on + * their event class. + */ +public interface EventSinkRegistry { + + /** + * Adds the specified sink for the given event class. + * + * @param eventClass event class + * @param sink event sink + * @param type of event + */ + void addSink(Class eventClass, EventSink sink); + + /** + * Removes the sink associated with the given event class. + * + * @param eventClass event class + * @param type of event + */ + void removeSink(Class eventClass); + + /** + * Returns the event sink associated with the specified event class. + * + * @param eventClass event class + * @param type of event + * @return event sink or null if none found + */ + EventSink getSink(Class eventClass); + + /** + * Returns the set of all event classes for which sinks are presently + * registered. + * + * @return set of event classes + */ + Set> getSinks(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/event/ListenerRegistry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/event/ListenerRegistry.java new file mode 100644 index 00000000..ef02af06 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/event/ListenerRegistry.java @@ -0,0 +1,99 @@ +/* + * Copyright 2014 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.event; + +import org.slf4j.Logger; + +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Base implementation of an event sink and a registry capable of tracking + * listeners and dispatching events to them as part of event sink processing. + */ +public class ListenerRegistry> + implements ListenerService, EventSink { + + private static final long LIMIT = 1_800; // ms + + private final Logger log = getLogger(getClass()); + + private long lastStart; + private L lastListener; + + /** + * Set of listeners that have registered. + */ + protected final Set listeners = new CopyOnWriteArraySet<>(); + + @Override + public void addListener(L listener) { + checkNotNull(listener, "Listener cannot be null"); + listeners.add(listener); + } + + @Override + public void removeListener(L listener) { + checkNotNull(listener, "Listener cannot be null"); + if (!listeners.remove(listener)) { + log.warn("Listener {} not registered", listener); + } + } + + @Override + public void process(E event) { + for (L listener : listeners) { + try { + lastListener = listener; + lastStart = System.currentTimeMillis(); + if (listener.isRelevant(event)) { + listener.event(event); + } + lastStart = 0; + } catch (Exception error) { + reportProblem(event, error); + } + } + } + + @Override + public void onProcessLimit() { + if (lastStart > 0) { + long duration = System.currentTimeMillis() - lastStart; + if (duration > LIMIT) { + log.error("Listener {} exceeded execution time limit: {} ms; ejected", + lastListener.getClass().getName(), + duration); + removeListener(lastListener); + } + lastStart = 0; + } + } + + /** + * Reports a problem encountered while processing an event. + * + * @param event event being processed + * @param error error encountered while processing + */ + protected void reportProblem(E event, Throwable error) { + log.warn("Exception encountered while processing event " + event, error); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/event/ListenerService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/event/ListenerService.java new file mode 100644 index 00000000..a4a36319 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/event/ListenerService.java @@ -0,0 +1,38 @@ +/* + * 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.event; + +/** + * Abstraction of a service capable of asynchronously notifying listeners. + */ +public interface ListenerService> { + + /** + * Adds the specified listener. + * + * @param listener listener to be added + */ + void addListener(L listener); + + /** + * Removes the specified listener. + * + * @param listener listener to be removed + */ + void removeListener(L listener); + + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/event/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/event/package-info.java new file mode 100644 index 00000000..6b10bcf5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/event/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Local event delivery subsystem interfaces & supporting abstractions. + */ +package org.onosproject.event; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipAdminService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipAdminService.java new file mode 100644 index 00000000..a8835fc7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipAdminService.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014 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.mastership; + +import java.util.concurrent.CompletableFuture; + +import org.onosproject.cluster.NodeId; +import org.onosproject.net.DeviceId; +import org.onosproject.net.MastershipRole; + +/** + * Service for administering the inventory of device masterships. + */ +public interface MastershipAdminService { + + /** + * Applies the current mastership role for the specified device. + * + * @param instance controller instance identifier + * @param deviceId device identifier + * @param role requested role + * @return future that is completed when the role is set + */ + CompletableFuture setRole(NodeId instance, DeviceId deviceId, MastershipRole role); + + /** + * Balances the mastership to be shared as evenly as possibly by all + * online instances. + */ + void balanceRoles(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipEvent.java new file mode 100644 index 00000000..35c32e79 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipEvent.java @@ -0,0 +1,95 @@ +/* + * Copyright 2014 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.mastership; + +import org.joda.time.LocalDateTime; +import org.onosproject.cluster.RoleInfo; +import org.onosproject.event.AbstractEvent; +import org.onosproject.net.DeviceId; + +import com.google.common.base.MoreObjects; + +/** + * Describes a device mastership event. + */ +public class MastershipEvent extends AbstractEvent { + + //Contains master and standby information. + RoleInfo roleInfo; + + /** + * Type of mastership events. + */ + public enum Type { + /** + * Signifies that the master for a device has changed. + */ + MASTER_CHANGED, + + /** + * Signifies that the list of backup nodes has changed. If + * the change in the backups list is accompanied by a change in + * master, the event is subsumed by MASTER_CHANGED. + */ + BACKUPS_CHANGED + } + + /** + * Creates an event of a given type and for the specified device, + * role information, and the current time. + * + * @param type mastership event type + * @param device event device subject + * @param info mastership role information + */ + public MastershipEvent(Type type, DeviceId device, RoleInfo info) { + super(type, device); + this.roleInfo = info; + } + + /** + * Creates an event of a given type and for the specified device, master, + * and time. + * + * @param type mastership event type + * @param device event device subject + * @param info role information + * @param time occurrence time + */ + public MastershipEvent(Type type, DeviceId device, RoleInfo info, long time) { + super(type, device, time); + this.roleInfo = info; + } + + /** + * Returns the current role state for the subject. + * + * @return RoleInfo associated with Device ID subject + */ + public RoleInfo roleInfo() { + return roleInfo; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("time", new LocalDateTime(time())) + .add("type", type()) + .add("subject", subject()) + .add("roleInfo", roleInfo) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipListener.java new file mode 100644 index 00000000..9c5690e2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipListener.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.mastership; + +import org.onosproject.event.EventListener; + +/** + * Entity capable of receiving device mastership-related events. + */ +public interface MastershipListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipService.java new file mode 100644 index 00000000..a709f5cf --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipService.java @@ -0,0 +1,101 @@ +/* + * Copyright 2014 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.mastership; + +import static org.onosproject.net.MastershipRole.MASTER; + +import java.util.Set; +import java.util.concurrent.CompletableFuture; + +import org.onosproject.cluster.NodeId; +import org.onosproject.cluster.RoleInfo; +import org.onosproject.event.ListenerService; +import org.onosproject.net.DeviceId; +import org.onosproject.net.MastershipRole; + +/** + * Service responsible for determining the controller instance mastership of + * a device in a clustered environment. This is the central authority for + * determining mastership, but is not responsible for actually applying it + * to the devices; this falls on the device service. + */ +public interface MastershipService + extends ListenerService { + + /** + * Returns the role of the local node for the specified device, without + * triggering master selection. + * + * @param deviceId the the identifier of the device + * @return role of the current node + */ + MastershipRole getLocalRole(DeviceId deviceId); + + /** + * Returns true if the local controller is the Master for the specified deviceId. + * + * @param deviceId the the identifier of the device + * @return true if local node is master; false otherwise + */ + default boolean isLocalMaster(DeviceId deviceId) { + return getLocalRole(deviceId) == MASTER; + } + + /** + * Returns the mastership status of the local controller for a given + * device forcing master selection if necessary. + * + * @param deviceId the the identifier of the device + * @return the role of this controller instance + */ + CompletableFuture requestRoleFor(DeviceId deviceId); + + /** + * Abandons mastership of the specified device on the local node thus + * forcing selection of a new master. If the local node is not a master + * for this device, no master selection will occur. + * + * @param deviceId the identifier of the device + * @return future that is completed when relinquish is complete + */ + CompletableFuture relinquishMastership(DeviceId deviceId); + + /** + * Returns the current master for a given device. + * + * @param deviceId the identifier of the device + * @return the ID of the master controller for the device + */ + NodeId getMasterFor(DeviceId deviceId); + + /** + * Returns controllers connected to a given device, in order of + * preference. The first entry in the list is the current master. + * + * @param deviceId the identifier of the device + * @return a list of controller IDs + */ + RoleInfo getNodesFor(DeviceId deviceId); + + /** + * Returns the devices for which a controller is master. + * + * @param nodeId the ID of the controller + * @return a set of device IDs + */ + Set getDevicesOf(NodeId nodeId); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipStore.java new file mode 100644 index 00000000..81c2d8b6 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipStore.java @@ -0,0 +1,125 @@ +/* + * Copyright 2014-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.mastership; + +import java.util.Set; +import java.util.concurrent.CompletableFuture; + +import org.onosproject.cluster.NodeId; +import org.onosproject.cluster.RoleInfo; +import org.onosproject.net.DeviceId; +import org.onosproject.net.MastershipRole; +import org.onosproject.store.Store; + +/** + * Manages inventory of mastership roles for devices, across controller + * instances; not intended for direct use. + */ +public interface MastershipStore extends Store { + + // three things to map: NodeId, DeviceId, MastershipRole + + /** + * Requests role of the local node for the specified device. + * + * @param deviceId device identifier + * @return established or newly negotiated mastership role + */ + CompletableFuture requestRole(DeviceId deviceId); + + /** + * Returns the role of a device for a specific controller instance. + * + * @param nodeId the instance identifier + * @param deviceId the device identifiers + * @return the role + */ + MastershipRole getRole(NodeId nodeId, DeviceId deviceId); + + /** + * Returns the master for a device. + * + * @param deviceId the device identifier + * @return the instance identifier of the master + */ + NodeId getMaster(DeviceId deviceId); + + /** + * Returns the master and backup nodes for a device. + * + * @param deviceId the device identifier + * @return a RoleInfo containing controller IDs + */ + RoleInfo getNodes(DeviceId deviceId); + + /** + * Returns the devices that a controller instance is master of. + * + * @param nodeId the instance identifier + * @return a set of device identifiers + */ + Set getDevices(NodeId nodeId); + + + /** + * Sets a device's role for a specified controller instance. + * + * @param nodeId controller instance identifier + * @param deviceId device identifier + * @return a mastership event + */ + CompletableFuture setMaster(NodeId nodeId, DeviceId deviceId); + + /** + * Returns the current master and number of past mastership hand-offs + * (terms) for a device. + * + * @param deviceId the device identifier + * @return the current master's ID and the term value for device, or null + */ + MastershipTerm getTermFor(DeviceId deviceId); + + /** + * Sets a controller instance's mastership role to STANDBY for a device. + * If the role is MASTER, another controller instance will be selected + * as a candidate master. + * + * @param nodeId the controller instance identifier + * @param deviceId device to revoke mastership role for + * @return a mastership event + */ + CompletableFuture setStandby(NodeId nodeId, DeviceId deviceId); + + /** + * Allows a controller instance to give up its current role for a device. + * If the role is MASTER, another controller instance will be selected + * as a candidate master. + * + * @param nodeId the controller instance identifier + * @param deviceId device to revoke mastership role for + * @return a mastership event + */ + CompletableFuture relinquishRole(NodeId nodeId, DeviceId deviceId); + + /** + * Removes all the roles for the specified controller instance. + * If the role was MASTER, another controller instance will be selected + * as a candidate master. + * + * @param nodeId the controller instance identifier + */ + void relinquishAllRole(NodeId nodeId); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipStoreDelegate.java new file mode 100644 index 00000000..c71f4ed0 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipStoreDelegate.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.mastership; + +import org.onosproject.store.StoreDelegate; + +/** + * Mastership store delegate abstraction. + */ +public interface MastershipStoreDelegate extends StoreDelegate { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipTerm.java b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipTerm.java new file mode 100644 index 00000000..049d1d2b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipTerm.java @@ -0,0 +1,71 @@ +/* + * Copyright 2014-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.mastership; + +import java.util.Objects; + +import org.onosproject.cluster.NodeId; + +import com.google.common.base.MoreObjects; + +public final class MastershipTerm { + + private final NodeId master; + private final long termNumber; + + private MastershipTerm(NodeId master, long term) { + this.master = master; + this.termNumber = term; + } + + public static MastershipTerm of(NodeId master, long term) { + return new MastershipTerm(master, term); + } + + public NodeId master() { + return master; + } + + public long termNumber() { + return termNumber; + } + + @Override + public int hashCode() { + return Objects.hash(master, termNumber); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other instanceof MastershipTerm) { + MastershipTerm that = (MastershipTerm) other; + return Objects.equals(this.master, that.master) && + Objects.equals(this.termNumber, that.termNumber); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("master", this.master) + .add("termNumber", this.termNumber) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipTermService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipTermService.java new file mode 100644 index 00000000..1725ee03 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/MastershipTermService.java @@ -0,0 +1,35 @@ +/* + * Copyright 2014 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.mastership; + +import org.onosproject.net.DeviceId; + +// TODO give me a better name +/** + * Service to obtain mastership term information. + */ +public interface MastershipTermService { + + // TBD: manage/increment per device mastership change + // or increment on any change + /** + * Returns the term number of mastership change occurred for given device. + * + * @param deviceId the identifier of the device + * @return current master's term. + */ + MastershipTerm getMastershipTerm(DeviceId deviceId); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/package-info.java new file mode 100644 index 00000000..0040680a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/mastership/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Set of abstractions for dealing with controller mastership related topics. + */ +package org.onosproject.mastership; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractAnnotated.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractAnnotated.java new file mode 100644 index 00000000..e0407e27 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractAnnotated.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014-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 static com.google.common.base.Preconditions.checkArgument; +import static org.onosproject.net.DefaultAnnotations.EMPTY; + +/** + * Base abstraction of an annotated entity. + */ +public abstract class AbstractAnnotated implements Annotated { + + private final Annotations annotations; + + // For serialization + protected AbstractAnnotated() { + this.annotations = null; + } + + /** + * Creates a new entity, annotated with the specified annotations. + * + * @param annotations optional key/value annotations map + */ + protected AbstractAnnotated(Annotations... annotations) { + checkArgument(annotations.length <= 1, "Only one set of annotations is expected"); + this.annotations = annotations.length == 1 ? annotations[0] : EMPTY; + } + + @Override + public Annotations annotations() { + return annotations; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractDescription.java new file mode 100644 index 00000000..d81b83cc --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractDescription.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 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 static com.google.common.base.Preconditions.checkArgument; + +/** + * Base implementation of an annotated model description. + */ +public abstract class AbstractDescription implements Annotated { + + private static final SparseAnnotations EMPTY = DefaultAnnotations.builder().build(); + + private final SparseAnnotations annotations; + + // For serialization + protected AbstractDescription() { + this.annotations = null; + } + + /** + * Creates a new entity, annotated with the specified annotations. + * + * @param annotations optional key/value annotations map + */ + protected AbstractDescription(SparseAnnotations... annotations) { + checkArgument(annotations.length <= 1, "Only one set of annotations is expected"); + this.annotations = annotations.length == 1 ? annotations[0] : EMPTY; + } + + @Override + public SparseAnnotations annotations() { + return annotations; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractElement.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractElement.java new file mode 100644 index 00000000..595e7b9c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractElement.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014 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; + +/** + * Base implementation of network elements, i.e. devices or hosts. + */ +public abstract class AbstractElement extends AbstractModel implements Element { + + protected final ElementId id; + + // For serialization + public AbstractElement() { + id = null; + } + + /** + * Creates a network element attributed to the specified provider. + * + * @param providerId identity of the provider + * @param id element identifier + * @param annotations optional key/value annotations + */ + protected AbstractElement(ProviderId providerId, ElementId id, + Annotations... annotations) { + super(providerId, annotations); + this.id = id; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractModel.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractModel.java new file mode 100644 index 00000000..f3cd5efe --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AbstractModel.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 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; + +/** + * Base implementation of a network model entity. + */ +public abstract class AbstractModel extends AbstractAnnotated implements Provided { + + private final ProviderId providerId; + + // For serialization + public AbstractModel() { + providerId = null; + } + + /** + * Creates a model entity attributed to the specified provider and + * optionally annotated. + * + * @param providerId identity of the provider + * @param annotations optional key/value annotations + */ + protected AbstractModel(ProviderId providerId, Annotations... annotations) { + super(annotations); + this.providerId = providerId; + } + + @Override + public ProviderId providerId() { + return providerId; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/Annotated.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Annotated.java new file mode 100644 index 00000000..ac4545ac --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Annotated.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014 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; + +/** + * Represents an entity that carries arbitrary annotations. + */ +public interface Annotated { + + /** + * Returns the key/value annotations. + * + * @return key/value annotations + */ + Annotations annotations(); + +} 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 new file mode 100644 index 00000000..4949bc40 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationKeys.java @@ -0,0 +1,145 @@ +/* + * Copyright 2014-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; + +/** + * Collection of keys for annotation. + *

+ * Number of the annotation keys have been deprecated as the use of annotations + * is being phased out and instead network configuration subsystem is being + * phased-in for majority of model meta-data. + *

+ */ +public final class AnnotationKeys { + + // Prohibit instantiation + private AnnotationKeys() {} + + /** + * Annotation key for instance name. + * + * @deprecated since Cardinal + */ + @Deprecated + public static final String NAME = "name"; + + /** + * Annotation key for instance type (e.g. host type). + * + * @deprecated since Cardinal + */ + @Deprecated + public static final String TYPE = "type"; + + /** + * Annotation key for latitude (e.g. latitude of device). + * + * @deprecated since Cardinal + */ + @Deprecated + public static final String LATITUDE = "latitude"; + + /** + * Annotation key for longitute (e.g. longitude of device). + * + * @deprecated since Cardinal + */ + @Deprecated + public static final String LONGITUDE = "longitude"; + + /** + * Annotation key for southbound protocol. + */ + public static final String PROTOCOL = "protocol"; + + /** + * Annotation key for the device driver name. + * + * @deprecated since Cardinal + */ + @Deprecated + public static final String DRIVER = "driver"; + + /** + * Annotation key for durable links. + */ + public static final String DURABLE = "durable"; + + /** + * Annotation key for latency. + * + * @deprecated since Cardinal + */ + @Deprecated + public static final String LATENCY = "latency"; + + /** + * Annotation key for bandwidth. + * The value for this key is interpreted as Mbps. + * + * @deprecated since Cardinal + */ + @Deprecated + public static final String BANDWIDTH = "bandwidth"; + + /** + * Annotation key for the number of optical waves. + */ + public static final String OPTICAL_WAVES = "optical.waves"; + + /** + * Annotation key for the port name. + */ + public static final String PORT_NAME = "portName"; + + /** + * Annotation key for the router ID. + */ + public static final String ROUTER_ID = "routerId"; + + public static final String STATIC_LAMBDA = "staticLambda"; + + public static final String STATIC_PORT = "staticPort"; + + /** + * Annotation key for device location. + */ + public static final String RACK_ADDRESS = "rackAddress"; + + /** + * Annotation key for device owner. + */ + public static final String OWNER = "owner"; + + /** + * 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 + * @return double value of annotated object for the specified key + */ + public static double getAnnotatedValue(Annotated annotated, String key) { + double value; + try { + value = Double.parseDouble(annotated.annotations().value(key)); + } catch (NumberFormatException e) { + value = 1.0; + } + return value; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/Annotations.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Annotations.java new file mode 100644 index 00000000..4ed70601 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Annotations.java @@ -0,0 +1,40 @@ +/* + * Copyright 2014 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 java.util.Set; + +/** + * Represents an set of simple key/value string annotations. + */ +public interface Annotations { + + /** + * Returns the set of keys for available annotations. + * + * @return annotation keys + */ + Set keys(); + + /** + * Returns the value of the specified annotation. + * + * @param key annotation key + * @return annotation value + */ + String value(String key); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationsUtil.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationsUtil.java new file mode 100644 index 00000000..d43a304d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/AnnotationsUtil.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014 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; + +/** + * Utility for processing annotations. + */ +public final class AnnotationsUtil { + + public static boolean isEqual(Annotations lhs, Annotations rhs) { + if (lhs == rhs) { + return true; + } + if (lhs == null || rhs == null) { + return false; + } + + if (!lhs.keys().equals(rhs.keys())) { + return false; + } + + for (String key : lhs.keys()) { + if (!lhs.value(key).equals(rhs.value(key))) { + return false; + } + } + return true; + } + + // not to be instantiated + private AnnotationsUtil() {} +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/ChannelSpacing.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/ChannelSpacing.java new file mode 100644 index 00000000..4da9d6b3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/ChannelSpacing.java @@ -0,0 +1,44 @@ +/* + * 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.onlab.util.Frequency; + +/** + * Represents interval frequency between two neighboring wavelengths. + */ +public enum ChannelSpacing { + CHL_100GHZ(100), // 100 GHz + CHL_50GHZ(50), // 50 GHz + CHL_25GHZ(25), // 25 GHz + CHL_12P5GHZ(12.5), // 12.5 GHz + CHL_6P25GHZ(6.5); // 6.25 GHz + + private final Frequency frequency; + + /** + * Creates an instance with the specified interval in GHz. + * + * @param value interval of neighboring wavelengths in GHz. + */ + ChannelSpacing(double value) { + this.frequency = Frequency.ofGHz(value); + } + + public Frequency frequency() { + return frequency; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/ConnectPoint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/ConnectPoint.java new file mode 100644 index 00000000..0d13f4aa --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/ConnectPoint.java @@ -0,0 +1,175 @@ +/* + * Copyright 2014 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 com.google.common.base.MoreObjects; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Abstraction of a network connection point expressed as a pair of the + * network element identifier and port number. + */ +public class ConnectPoint { + + private final ElementId elementId; + private final PortNumber portNumber; + + /** + * Creates a new connection point. + * + * @param elementId network element identifier + * @param portNumber port number + */ + public ConnectPoint(ElementId elementId, PortNumber portNumber) { + this.elementId = elementId; + this.portNumber = portNumber; + } + + /** + * Returns the network element identifier. + * + * @return element identifier + */ + public ElementId elementId() { + return elementId; + } + + /** + * Returns the identifier of the infrastructure device if the connection + * point belongs to a network element which is indeed an infrastructure + * device. + * + * @return network element identifier as a device identifier + * @throws java.lang.IllegalStateException if connection point is not + * associated with a device + */ + public DeviceId deviceId() { + if (elementId instanceof DeviceId) { + return (DeviceId) elementId; + } + throw new IllegalStateException("Connection point not associated " + + "with an infrastructure device"); + } + + /** + * Returns the identifier of the infrastructure device if the connection + * point belongs to a network element which is indeed an end-station host. + * + * @return network element identifier as a host identifier + * @throws java.lang.IllegalStateException if connection point is not + * associated with a host + */ + public HostId hostId() { + if (elementId instanceof HostId) { + return (HostId) elementId; + } + throw new IllegalStateException("Connection point not associated " + + "with an end-station host"); + } + + /** + * Returns the identifier of the infrastructure device if the connection + * point belongs to a network element which is indeed an ip of pcc + * client identifier. + * + * @return network element identifier as a pcc client identifier + * @throws java.lang.IllegalStateException if connection point is not + * associated with a pcc client + */ + public IpElementId ipElementId() { + if (elementId instanceof IpElementId) { + return (IpElementId) elementId; + } + throw new IllegalStateException("Connection point not associated " + + "with an pcc client"); + } + + /** + * Returns the connection port number. + * + * @return port number + */ + public PortNumber port() { + return portNumber; + } + + /** + * Parse a device connect point from a string. + * The connect point should be in the format "deviceUri/portNumber". + * + * @param string string to parse + * @return a ConnectPoint based on the information in the string. + */ + public static ConnectPoint deviceConnectPoint(String string) { + checkNotNull(string); + String[] splitted = string.split("/"); + checkArgument(splitted.length == 2, + "Connect point must be in \"deviceUri/portNumber\" format"); + + return new ConnectPoint(DeviceId.deviceId(splitted[0]), + PortNumber.portNumber(splitted[1])); + } + + /** + * Parse a host connect point from a string. + * The connect point should be in the format "hostId/vlanId/portNumber". + * + * @param string string to parse + * @return a ConnectPoint based on the information in the string. + */ + public static ConnectPoint hostConnectPoint(String string) { + checkNotNull(string); + String[] splitted = string.split("/"); + checkArgument(splitted.length == 3, + "Connect point must be in \"hostId/vlanId/portNumber\" format"); + + int lastSlash = string.lastIndexOf("/"); + + return new ConnectPoint(HostId.hostId(string.substring(0, lastSlash)), + PortNumber.portNumber(string.substring(lastSlash + 1, string.length()))); + } + + @Override + public int hashCode() { + return Objects.hash(elementId, portNumber); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ConnectPoint) { + final ConnectPoint other = (ConnectPoint) obj; + return Objects.equals(this.elementId, other.elementId) && + Objects.equals(this.portNumber, other.portNumber); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("elementId", elementId) + .add("portNumber", portNumber) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultAnnotations.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultAnnotations.java new file mode 100644 index 00000000..7c97ecdd --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultAnnotations.java @@ -0,0 +1,254 @@ +/* + * Copyright 2014-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 java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import com.google.common.collect.Maps; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a set of simple annotations that can be used to add arbitrary + * attributes to various parts of the data model. + */ +public final class DefaultAnnotations implements SparseAnnotations { + + public static final SparseAnnotations EMPTY = DefaultAnnotations.builder().build(); + + private final Map map; + + // For serialization + private DefaultAnnotations() { + this.map = null; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + DefaultAnnotations that = (DefaultAnnotations) o; + + return Objects.equals(this.map, that.map); + + } + + @Override + public int hashCode() { + return Objects.hashCode(this.map); + } + + /** + * Returns the annotations as a map. + * + * @return a copy of the contents of the annotations as a map. + */ + public HashMap asMap() { + return Maps.newHashMap(this.map); + } + + /** + * Creates a new set of annotations using clone of the specified hash map. + * + * @param map hash map of key/value pairs + */ + private DefaultAnnotations(Map map) { + this.map = map; + } + + /** + * Creates a new annotations builder. + * + * @return new annotations builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Merges the specified base set of annotations and additional sparse + * annotations into new combined annotations. If the supplied sparse + * annotations are empty, the original base annotations are returned. + * Any keys tagged for removal in the sparse annotations will be omitted + * in the resulting merged annotations. + * + * @param annotations base annotations + * @param sparseAnnotations additional sparse annotations + * @return combined annotations or the original base annotations if there + * are not additional annotations + */ + public static DefaultAnnotations merge(DefaultAnnotations annotations, + SparseAnnotations sparseAnnotations) { + checkNotNull(annotations, "Annotations cannot be null"); + if (sparseAnnotations == null || sparseAnnotations.keys().isEmpty()) { + return annotations; + } + + // Merge the two maps. Yes, this is not very efficient, but the + // use-case implies small maps and infrequent merges, so we opt for + // simplicity. + Map merged = copy(annotations.map); + for (String key : sparseAnnotations.keys()) { + if (sparseAnnotations.isRemoved(key)) { + merged.remove(key); + } else { + merged.put(key, sparseAnnotations.value(key)); + } + } + return new DefaultAnnotations(merged); + } + + /** + * Creates the union of two given SparseAnnotations. + * Unlike the {@link #merge(DefaultAnnotations, SparseAnnotations)} method, + * result will be {@link SparseAnnotations} instead of {@link Annotations}. + * + * A key tagged for removal will remain in the output SparseAnnotations, + * if the counterpart of the input does not contain the same key. + * + * @param annotations base annotations + * @param sparseAnnotations additional sparse annotations + * @return combined annotations or the original base annotations if there + * are not additional annotations + */ + public static SparseAnnotations union(SparseAnnotations annotations, + SparseAnnotations sparseAnnotations) { + + if (sparseAnnotations == null || sparseAnnotations.keys().isEmpty()) { + return annotations; + } + + final HashMap newMap; + if (annotations instanceof DefaultAnnotations) { + newMap = copy(((DefaultAnnotations) annotations).map); + } else { + newMap = new HashMap<>(annotations.keys().size() + + sparseAnnotations.keys().size()); + putAllSparseAnnotations(newMap, annotations); + } + + putAllSparseAnnotations(newMap, sparseAnnotations); + return new DefaultAnnotations(newMap); + } + + // adds the key-values contained in sparseAnnotations to + // newMap, if sparseAnnotations had a key tagged for removal, + // and corresponding key exist in newMap, entry will be removed. + // if corresponding key does not exist, removal tag will be added to + // the newMap. + private static void putAllSparseAnnotations( + final HashMap newMap, + SparseAnnotations sparseAnnotations) { + + for (String key : sparseAnnotations.keys()) { + if (sparseAnnotations.isRemoved(key)) { + if (newMap.containsKey(key)) { + newMap.remove(key); + } else { + newMap.put(key, Builder.REMOVED); + } + } else { + String value = sparseAnnotations.value(key); + newMap.put(key, value); + } + } + } + + @Override + public Set keys() { + return Collections.unmodifiableSet(map.keySet()); + } + + @Override + public String value(String key) { + String value = map.get(key); + return Objects.equals(Builder.REMOVED, value) ? null : value; + } + + @Override + public boolean isRemoved(String key) { + return Objects.equals(Builder.REMOVED, map.get(key)); + } + + @SuppressWarnings("unchecked") + private static HashMap copy(Map original) { + if (original instanceof HashMap) { + return (HashMap) ((HashMap) original).clone(); + } + throw new IllegalArgumentException("Expecting HashMap instance"); + } + + @Override + public String toString() { + return (map == null) ? "null" : map.toString(); + } + + /** + * Facility for gradually building model annotations. + */ + public static final class Builder { + + private static final String REMOVED = "~rEmOvEd~"; + private final Map builder = new HashMap<>(); + + // Private construction is forbidden. + private Builder() { + } + + /** + * Adds the specified annotation. Any previous value associated with + * the given annotation key will be overwritten. + * + * @param key annotation key + * @param value annotation value + * @return self + */ + public Builder set(String key, String value) { + builder.put(key, value); + return this; + } + + /** + * Adds the specified annotation. Any previous value associated with + * the given annotation key will be tagged for removal. + * + * @param key annotation key + * @return self + */ + public Builder remove(String key) { + builder.put(key, REMOVED); + return this; + } + + /** + * Returns immutable annotations built from the accrued key/values pairs. + * + * @return annotations + */ + public DefaultAnnotations build() { + return new DefaultAnnotations(copy(builder)); + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultDevice.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultDevice.java new file mode 100644 index 00000000..f3f0fe74 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultDevice.java @@ -0,0 +1,142 @@ +/* + * Copyright 2014-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 org.onlab.packet.ChassisId; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Default infrastructure device model implementation. + */ +public class DefaultDevice extends AbstractElement implements Device { + + private final Type type; + private final String manufacturer; + private final String serialNumber; + private final String hwVersion; + private final String swVersion; + private final ChassisId chassisId; + + // For serialization + private DefaultDevice() { + this.type = null; + this.manufacturer = null; + this.hwVersion = null; + this.swVersion = null; + this.serialNumber = null; + this.chassisId = null; + } + + /** + * Creates a network element attributed to the specified provider. + * + * @param providerId identity of the provider + * @param id device identifier + * @param type device type + * @param manufacturer device manufacturer + * @param hwVersion device HW version + * @param swVersion device SW version + * @param serialNumber device serial number + * @param chassisId chassis id + * @param annotations optional key/value annotations + */ + public DefaultDevice(ProviderId providerId, DeviceId id, Type type, + String manufacturer, String hwVersion, String swVersion, + String serialNumber, ChassisId chassisId, + Annotations... annotations) { + super(providerId, id, annotations); + this.type = type; + this.manufacturer = manufacturer; + this.hwVersion = hwVersion; + this.swVersion = swVersion; + this.serialNumber = serialNumber; + this.chassisId = chassisId; + } + + @Override + public DeviceId id() { + return (DeviceId) id; + } + + @Override + public Type type() { + return type; + } + + @Override + public String manufacturer() { + return manufacturer; + } + + @Override + public String hwVersion() { + return hwVersion; + } + + @Override + public String swVersion() { + return swVersion; + } + + @Override + public String serialNumber() { + return serialNumber; + } + + @Override + public ChassisId chassisId() { + return chassisId; + } + + @Override + public int hashCode() { + return Objects.hash(id, type, manufacturer, hwVersion, swVersion, serialNumber); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultDevice) { + final DefaultDevice other = (DefaultDevice) obj; + return Objects.equals(this.id, other.id) && + Objects.equals(this.type, other.type) && + Objects.equals(this.manufacturer, other.manufacturer) && + Objects.equals(this.hwVersion, other.hwVersion) && + Objects.equals(this.swVersion, other.swVersion) && + Objects.equals(this.serialNumber, other.serialNumber); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("id", id) + .add("type", type) + .add("manufacturer", manufacturer) + .add("hwVersion", hwVersion) + .add("swVersion", swVersion) + .add("serialNumber", serialNumber) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultEdgeLink.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultEdgeLink.java new file mode 100644 index 00000000..67ceef7a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultEdgeLink.java @@ -0,0 +1,96 @@ +/* + * Copyright 2014 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 static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default edge link model implementation. + */ +public class DefaultEdgeLink extends DefaultLink implements EdgeLink { + + private final HostId hostId; + private final HostLocation hostLocation; + + /** + * Creates an edge link using the supplied information. + * + * @param providerId provider identity + * @param hostPoint host-side connection point + * @param hostLocation location where host attaches to the network + * @param isIngress true to indicate host-to-network direction; false + * for network-to-host direction + * @param annotations optional key/value annotations + */ + public DefaultEdgeLink(ProviderId providerId, ConnectPoint hostPoint, + HostLocation hostLocation, boolean isIngress, + Annotations... annotations) { + super(providerId, isIngress ? hostPoint : hostLocation, + isIngress ? hostLocation : hostPoint, Type.EDGE, annotations); + checkArgument(hostPoint.elementId() instanceof HostId, + "Host point does not refer to a host ID"); + this.hostId = (HostId) hostPoint.elementId(); + this.hostLocation = hostLocation; + } + + @Override + public HostId hostId() { + return hostId; + } + + @Override + public HostLocation hostLocation() { + return hostLocation; + } + + /** + * Creates a phantom edge link, to an unspecified end-station. This link + * does not represent any actually discovered link stored in the system. + * + * @param edgePort network edge port + * @param isIngress true to indicate host-to-network direction; false + * for network-to-host direction + * @return new phantom edge link + */ + public static DefaultEdgeLink createEdgeLink(ConnectPoint edgePort, + boolean isIngress) { + checkNotNull(edgePort, "Edge port cannot be null"); + HostLocation location = (edgePort instanceof HostLocation) ? + (HostLocation) edgePort : new HostLocation(edgePort, 0); + return new DefaultEdgeLink(ProviderId.NONE, + new ConnectPoint(HostId.NONE, PortNumber.P0), + location, isIngress); + } + + /** + * Creates a an edge link, to the specified end-station. + * + * @param host host + * @param isIngress true to indicate host-to-network direction; false + * for network-to-host direction + * @return new phantom edge link + */ + public static DefaultEdgeLink createEdgeLink(Host host, boolean isIngress) { + checkNotNull(host, "Host cannot be null"); + return new DefaultEdgeLink(ProviderId.NONE, + new ConnectPoint(host.id(), PortNumber.P0), + host.location(), isIngress); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultHost.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultHost.java new file mode 100644 index 00000000..2877701e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultHost.java @@ -0,0 +1,117 @@ +/* + * Copyright 2014 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 org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * A basic implementation of a Host. + */ +public class DefaultHost extends AbstractElement implements Host { + + private final MacAddress mac; + private final VlanId vlan; + private final HostLocation location; + private final Set ips; + + /** + * Creates an end-station host using the supplied information. + * + * @param providerId provider identity + * @param id host identifier + * @param mac host MAC address + * @param vlan host VLAN identifier + * @param location host location + * @param ips host IP addresses + * @param annotations optional key/value annotations + */ + public DefaultHost(ProviderId providerId, HostId id, MacAddress mac, + VlanId vlan, HostLocation location, Set ips, + Annotations... annotations) { + super(providerId, id, annotations); + this.mac = mac; + this.vlan = vlan; + this.location = location; + this.ips = new HashSet<>(ips); + } + + @Override + public HostId id() { + return (HostId) id; + } + + @Override + public MacAddress mac() { + return mac; + } + + @Override + public Set ipAddresses() { + return Collections.unmodifiableSet(ips); + } + + @Override + public HostLocation location() { + return location; + } + + @Override + public VlanId vlan() { + return vlan; + } + + @Override + public int hashCode() { + return Objects.hash(id, mac, vlan, location); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultHost) { + final DefaultHost other = (DefaultHost) obj; + return Objects.equals(this.id, other.id) && + Objects.equals(this.mac, other.mac) && + Objects.equals(this.vlan, other.vlan) && + Objects.equals(this.location, other.location); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("id", id) + .add("mac", mac) + .add("vlan", vlan) + .add("location", location) + .add("ipAddresses", ips) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultLink.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultLink.java new file mode 100644 index 00000000..4d1ca6de --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultLink.java @@ -0,0 +1,131 @@ +/* + * Copyright 2014 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.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static org.onosproject.net.Link.State.ACTIVE; + +/** + * Default infrastructure link model implementation. + */ +public class DefaultLink extends AbstractModel implements Link { + + private final ConnectPoint src; + private final ConnectPoint dst; + private final Type type; + private final State state; + private final boolean isDurable; + + /** + * Creates an active infrastructure link using the supplied information. + * + * @param providerId provider identity + * @param src link source + * @param dst link destination + * @param type link type + * @param annotations optional key/value annotations + */ + public DefaultLink(ProviderId providerId, ConnectPoint src, ConnectPoint dst, + Type type, Annotations... annotations) { + this(providerId, src, dst, type, ACTIVE, false, annotations); + } + + /** + * Creates an infrastructure link using the supplied information. + * Links marked as durable will remain in the inventory when a vanish + * message is received and instead will be marked as inactive. + * + * @param providerId provider identity + * @param src link source + * @param dst link destination + * @param type link type + * @param state link state + * @param isDurable indicates if the link is to be considered durable + * @param annotations optional key/value annotations + */ + public DefaultLink(ProviderId providerId, ConnectPoint src, ConnectPoint dst, + Type type, State state, + boolean isDurable, Annotations... annotations) { + super(providerId, annotations); + this.src = src; + this.dst = dst; + this.type = type; + this.state = state; + this.isDurable = isDurable; + } + + @Override + public ConnectPoint src() { + return src; + } + + @Override + public ConnectPoint dst() { + return dst; + } + + @Override + public Type type() { + return type; + } + + @Override + public State state() { + return state; + } + + @Override + public boolean isDurable() { + return isDurable; + } + + // Note: Durability & state are purposefully omitted form equality & hashCode. + + @Override + public int hashCode() { + return Objects.hash(src, dst, type); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultLink) { + final DefaultLink other = (DefaultLink) obj; + return Objects.equals(this.src, other.src) && + Objects.equals(this.dst, other.dst) && + Objects.equals(this.type, other.type); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("src", src) + .add("dst", dst) + .add("type", type) + .add("state", state) + .add("durable", isDurable) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultPath.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultPath.java new file mode 100644 index 00000000..a4789cac --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultPath.java @@ -0,0 +1,105 @@ +/* + * Copyright 2014 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 com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; +import org.onosproject.net.provider.ProviderId; + +import java.util.List; +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default implementation of a network path. + */ +public class DefaultPath extends DefaultLink implements Path { + + private final List links; + private final double cost; + + /** + * Creates a path from the specified source and destination using the + * supplied list of links. + * + * @param providerId provider identity + * @param links contiguous links that comprise the path + * @param cost unit-less path cost + * @param annotations optional key/value annotations + */ + public DefaultPath(ProviderId providerId, List links, double cost, + Annotations... annotations) { + super(providerId, source(links), destination(links), Type.INDIRECT, annotations); + this.links = ImmutableList.copyOf(links); + this.cost = cost; + } + + @Override + public List links() { + return links; + } + + @Override + public double cost() { + return cost; + } + + // Returns the source of the first link. + private static ConnectPoint source(List links) { + checkNotNull(links, "List of path links cannot be null"); + checkArgument(!links.isEmpty(), "List of path links cannot be empty"); + return links.get(0).src(); + } + + // Returns the destination of the last link. + private static ConnectPoint destination(List links) { + checkNotNull(links, "List of path links cannot be null"); + checkArgument(!links.isEmpty(), "List of path links cannot be empty"); + return links.get(links.size() - 1).dst(); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("src", src()) + .add("dst", dst()) + .add("type", type()) + .add("state", state()) + .add("durable", isDurable()) + .add("links", links) + .add("cost", cost) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(links); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultPath) { + final DefaultPath other = (DefaultPath) obj; + return Objects.equals(this.links, other.links); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultPort.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultPort.java new file mode 100644 index 00000000..a6b8441a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DefaultPort.java @@ -0,0 +1,127 @@ +/* + * Copyright 2014 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 java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Default port implementation. + */ +public class DefaultPort extends AbstractAnnotated implements Port { + + /** Default port speed in Mbps. */ + public static final long DEFAULT_SPEED = 1_000; + + private final Element element; + private final PortNumber number; + private final boolean isEnabled; + private final Type type; + private final long portSpeed; + + /** + * Creates a network element attributed to the specified provider. + * + * @param element parent network element + * @param number port number + * @param isEnabled indicator whether the port is up and active + * @param annotations optional key/value annotations + */ + public DefaultPort(Element element, PortNumber number, boolean isEnabled, + Annotations... annotations) { + this(element, number, isEnabled, Type.COPPER, DEFAULT_SPEED, annotations); + } + + /** + * Creates a network element attributed to the specified provider. + * + * @param element parent network element + * @param number port number + * @param isEnabled indicator whether the port is up and active + * @param type port type + * @param portSpeed port speed in Mbs + * @param annotations optional key/value annotations + */ + public DefaultPort(Element element, PortNumber number, boolean isEnabled, + Type type, long portSpeed, Annotations... annotations) { + super(annotations); + this.element = element; + this.number = number; + this.isEnabled = isEnabled; + this.type = type; + this.portSpeed = portSpeed; + } + + @Override + public Element element() { + return element; + } + + @Override + public PortNumber number() { + return number; + } + + @Override + public boolean isEnabled() { + return isEnabled; + } + + @Override + public Type type() { + return type; + } + + @Override + public long portSpeed() { + return portSpeed; + } + + @Override + public int hashCode() { + return Objects.hash(number, isEnabled, type, portSpeed, annotations()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultPort) { + final DefaultPort other = (DefaultPort) obj; + return Objects.equals(this.element.id(), other.element.id()) && + Objects.equals(this.number, other.number) && + Objects.equals(this.isEnabled, other.isEnabled) && + Objects.equals(this.type, other.type) && + Objects.equals(this.portSpeed, other.portSpeed) && + Objects.equals(this.annotations(), other.annotations()); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("element", element.id()) + .add("number", number) + .add("isEnabled", isEnabled) + .add("type", type) + .add("portSpeed", portSpeed) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/Description.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Description.java new file mode 100644 index 00000000..c01af549 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Description.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 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; + +/** + * Base abstraction of a piece of information about network elements. + */ +public interface Description extends Annotated { + + @Override + SparseAnnotations annotations(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/Device.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Device.java new file mode 100644 index 00000000..d9001825 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Device.java @@ -0,0 +1,83 @@ +/* + * Copyright 2014-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.onlab.packet.ChassisId; + +/** + * Representation of a network infrastructure device. + */ +public interface Device extends Element { + + /** + * Coarse classification of the type of the infrastructure device. + */ + public enum Type { + SWITCH, ROUTER, ROADM, OTN, ROADM_OTN, FIREWALL, BALANCER, IPS, IDS, CONTROLLER, + VIRTUAL, FIBER_SWITCH, MICROWAVE, OTHER + } + + /** + * Returns the device identifier. + * + * @return device id + */ + @Override + DeviceId id(); + + /** + * Returns the type of the infrastructure device. + * + * @return type of the device + */ + Type type(); + + /** + * Returns the device manufacturer name. + * + * @return manufacturer name + */ + String manufacturer(); + + /** + * Returns the device hardware version. + * + * @return hardware version + */ + String hwVersion(); + + /** + * Returns the device software version. + * + * @return software version + */ + String swVersion(); + + /** + * Returns the device serial number. + * + * @return serial number + */ + String serialNumber(); + + /** + * Returns the device chassis id. + * + * @return chassis id + */ + ChassisId chassisId(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/DeviceId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DeviceId.java new file mode 100644 index 00000000..5331342e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/DeviceId.java @@ -0,0 +1,99 @@ +/* + * Copyright 2014 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 java.net.URI; +import java.util.Objects; + +/** + * Immutable representation of a device identity. + */ +public final class DeviceId extends ElementId { + + /** + * Represents either no device, or an unspecified device. + */ + public static final DeviceId NONE = deviceId("none:none"); + + private final URI uri; + private final String str; + + // Public construction is prohibited + private DeviceId(URI uri) { + this.uri = uri; + this.str = uri.toString().toLowerCase(); + } + + + // Default constructor for serialization + protected DeviceId() { + this.uri = null; + this.str = null; + } + + /** + * Creates a device id using the supplied URI. + * + * @param uri device URI + * @return DeviceId + */ + public static DeviceId deviceId(URI uri) { + return new DeviceId(uri); + } + + /** + * Creates a device id using the supplied URI string. + * + * @param string device URI string + * @return DeviceId + */ + public static DeviceId deviceId(String string) { + return deviceId(URI.create(string)); + } + + /** + * Returns the backing URI. + * + * @return backing URI + */ + public URI uri() { + return uri; + } + + @Override + public int hashCode() { + return Objects.hash(str); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DeviceId) { + final DeviceId that = (DeviceId) obj; + return this.getClass() == that.getClass() && + Objects.equals(this.str, that.str); + } + return false; + } + + @Override + public String toString() { + return str; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/EdgeLink.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/EdgeLink.java new file mode 100644 index 00000000..73b916b2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/EdgeLink.java @@ -0,0 +1,39 @@ +/* + * Copyright 2014 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; + +/** + * Abstraction of a link between an end-station host and the network + * infrastructure. + */ +public interface EdgeLink extends Link { + + /** + * Returns the host identification. + * + * @return host identifier + */ + HostId hostId(); + + /** + * Returns the connection point where the host attaches to the + * network infrastructure. + * + * @return host location point + */ + HostLocation hostLocation(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/Element.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Element.java new file mode 100644 index 00000000..6cdab9e4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Element.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014 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; + +/** + * Base abstraction of a network element, i.e. an infrastructure device or an end-station host. + */ +public interface Element extends Annotated, Provided { + + /** + * Returns the network element identifier. + * + * @return element identifier + */ + ElementId id(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/ElementId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/ElementId.java new file mode 100644 index 00000000..87defb26 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/ElementId.java @@ -0,0 +1,22 @@ +/* + * Copyright 2014-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; + +/** + * Immutable representation of a network element identity. + */ +public abstract class ElementId implements NetworkResource { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/GridType.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/GridType.java new file mode 100644 index 00000000..8e9bc5b9 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/GridType.java @@ -0,0 +1,29 @@ +/* + * 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; + +/** + * Represents type of wavelength grid. + * + *

+ * See Open Networking Foundation "Optical Transport Protocol Extensions Version 1.0". + *

+ */ +public enum GridType { + DWDM, // Dense Wavelength Division Multiplexing + CWDM, // Coarse WDM + FLEX // Flex Grid +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/Host.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Host.java new file mode 100644 index 00000000..646f2283 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Host.java @@ -0,0 +1,68 @@ +/* + * Copyright 2014 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.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; + +import java.util.Set; + +/** + * Abstraction of an end-station host on the network, essentially a NIC. + */ +public interface Host extends Element { + + /** + * Host identification. + * + * @return host id + */ + @Override + HostId id(); + + /** + * Returns the host MAC address. + * + * @return mac address + */ + MacAddress mac(); + + /** + * Returns the VLAN ID tied to this host. + * + * @return VLAN ID value + */ + VlanId vlan(); + + /** + * Returns set of IP addresses currently bound to the host MAC address. + * + * @return set of IP addresses; empty if no IP address is bound + */ + Set ipAddresses(); + + /** + * Returns the most recent host location where the host attaches to the + * network edge. + * + * @return host location + */ + HostLocation location(); + + // TODO: explore capturing list of recent locations to aid in mobility + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/HostId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/HostId.java new file mode 100644 index 00000000..3e0d2b24 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/HostId.java @@ -0,0 +1,129 @@ +/* + * Copyright 2014 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.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Immutable representation of a host identity. + */ +public final class HostId extends ElementId { + + /** + * Represents either no host, or an unspecified host; used for creating + * open ingress/egress edge links. + */ + public static final HostId NONE = new HostId(MacAddress.ZERO, VlanId.NONE); + + private static final int MAC_LENGTH = 17; + private static final int MIN_ID_LENGTH = 19; + + private final MacAddress mac; + private final VlanId vlanId; + + // Public construction is prohibited + private HostId(MacAddress mac, VlanId vlanId) { + this.mac = mac; + this.vlanId = vlanId; + } + + // Default constructor for serialization + private HostId() { + this.mac = null; + this.vlanId = null; + } + + /** + * Returns the host MAC address. + * + * @return MAC address + */ + public MacAddress mac() { + return mac; + } + + /** + * Returns the host vlan Id. + * + * @return vlan Id + */ + public VlanId vlanId() { + return vlanId; + } + + /** + * Creates a device id using the supplied ID string. + * + * @param string device URI string + * @return host identifier + */ + public static HostId hostId(String string) { + checkArgument(string.length() >= MIN_ID_LENGTH, + "Host ID must be at least %s characters", MIN_ID_LENGTH); + MacAddress mac = MacAddress.valueOf(string.substring(0, MAC_LENGTH)); + VlanId vlanId = VlanId.vlanId(Short.parseShort(string.substring(MAC_LENGTH + 1))); + return new HostId(mac, vlanId); + } + + /** + * Creates a device id using the supplied MAC & VLAN ID. + * + * @param mac mac address + * @param vlanId vlan identifier + * @return host identifier + */ + public static HostId hostId(MacAddress mac, VlanId vlanId) { + return new HostId(mac, vlanId); + } + + /** + * Creates a device id using the supplied MAC and default VLAN. + * + * @param mac mac address + * @return host identifier + */ + public static HostId hostId(MacAddress mac) { + return hostId(mac, VlanId.vlanId(VlanId.UNTAGGED)); + } + + public String toString() { + return mac + "/" + vlanId; + } + + @Override + public int hashCode() { + return Objects.hash(mac, vlanId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof HostId) { + final HostId other = (HostId) obj; + return Objects.equals(this.mac, other.mac) && + Objects.equals(this.vlanId, other.vlanId); + } + return false; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/HostLocation.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/HostLocation.java new file mode 100644 index 00000000..b0553a2b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/HostLocation.java @@ -0,0 +1,67 @@ +/* + * Copyright 2014 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 static org.onosproject.net.PortNumber.P0; + +/** + * Representation of a network edge location where an end-station host is + * connected. + */ +public class HostLocation extends ConnectPoint { + + /** + * Represents a no location or an unknown location. + */ + public static final HostLocation NONE = new HostLocation(DeviceId.NONE, P0, 0L); + + // Note that time is explicitly excluded from the notion of equality. + private final long time; + + /** + * Creates a new host location using the supplied device & port. + * + * @param deviceId device identity + * @param portNumber device port number + * @param time time when detected, in millis since start of epoch + */ + public HostLocation(DeviceId deviceId, PortNumber portNumber, long time) { + super(deviceId, portNumber); + this.time = time; + } + + /** + * Creates a new host location derived from the supplied connection point. + * + * @param connectPoint connection point + * @param time time when detected, in millis since start of epoch + */ + public HostLocation(ConnectPoint connectPoint, long time) { + super(connectPoint.deviceId(), connectPoint.port()); + this.time = time; + } + + /** + * Returns the time when the location was established, given in + * milliseconds since start of epoch. + * + * @return time in milliseconds since start of epoch + */ + public long time() { + return time; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/IndexedLambda.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/IndexedLambda.java new file mode 100644 index 00000000..6b5fa652 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/IndexedLambda.java @@ -0,0 +1,71 @@ +/* + * 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 com.google.common.base.MoreObjects; + +/** + * Implementation of Lambda simply designated by an index number of wavelength. + */ +public class IndexedLambda implements Lambda { + + private final long index; + + /** + * Creates an instance representing the wavelength specified by the given index number. + * It is recommended to use {@link Lambda#indexedLambda(long)} unless you want to use the + * concrete type, IndexedLambda, directly. + * + * @param index index number of wavelength + */ + public IndexedLambda(long index) { + this.index = index; + } + + /** + * Returns the index number of lambda. + * + * @return the index number of lambda + */ + public long index() { + return index; + } + + @Override + public int hashCode() { + return Long.hashCode(index); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof IndexedLambda)) { + return false; + } + + final IndexedLambda that = (IndexedLambda) obj; + return this.index == that.index; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("lambda", index) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/IpElementId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/IpElementId.java new file mode 100644 index 00000000..9e19b624 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/IpElementId.java @@ -0,0 +1,61 @@ +package org.onosproject.net; + +import java.util.Objects; +import org.onlab.packet.IpAddress; +import com.google.common.base.MoreObjects; + +/** + * Represent for a Element ID using ip address. + */ +public final class IpElementId extends ElementId { + + private final IpAddress ipAddress; + + /** + * Public construction is prohibited. + * @param ipAddress ip address + */ + private IpElementId(IpAddress ipAddress) { + this.ipAddress = ipAddress; + } + + /** + * Create a IP Element ID. + * @param ipAddress IP address + * @return IpElementId + */ + public static IpElementId ipElement(IpAddress ipAddress) { + return new IpElementId(ipAddress); + } + + /** + * Returns the ip address. + * + * @return ipAddress + */ + public IpAddress ipAddress() { + return ipAddress; + } + + @Override + public int hashCode() { + return Objects.hash(ipAddress); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof IpElementId) { + final IpElementId other = (IpElementId) obj; + return Objects.equals(this.ipAddress, other.ipAddress); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()).add("ipAddress", ipAddress).toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/Lambda.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Lambda.java new file mode 100644 index 00000000..47d0d5f0 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Lambda.java @@ -0,0 +1,45 @@ +/* + * 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; + +/** + * Abstraction of wavelength. Currently, this is just a marker interface + */ +public interface Lambda { + /** + * Create an Lambda instance with the specified wavelength index number. + * + * @param lambda index number + * @return an instance + */ + static Lambda indexedLambda(long lambda) { + return new IndexedLambda(lambda); + } + + /** + * Creates a Lambda instance with the specified arguments. + * + * @param gridType grid type + * @param channelSpacing channel spacing + * @param spacingMultiplier channel spacing multiplier + * @param slotGranularity slot width granularity + * @return new lambda with specified arguments + */ + static Lambda ochSignal(GridType gridType, ChannelSpacing channelSpacing, + int spacingMultiplier, int slotGranularity) { + return new OchSignal(gridType, channelSpacing, spacingMultiplier, slotGranularity); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/Link.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Link.java new file mode 100644 index 00000000..7541f751 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Link.java @@ -0,0 +1,114 @@ +/* + * Copyright 2014 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; + +/** + * Abstraction of a network infrastructure link. + */ +public interface Link extends Annotated, Provided, NetworkResource { + + /** + * Coarse representation of the link type. + */ + enum Type { + /** + * Signifies that this is a direct single-segment link. + */ + DIRECT, + + /** + * Signifies that this link is potentially comprised from multiple + * underlying segments or hops, and as such should be used to tag + * links traversing optical paths, tunnels or intervening 'dark' + * switches. + */ + INDIRECT, + + /** + * Signifies that this link is an edge, i.e. host link. + */ + EDGE, + + /** + * Signifies that this link represents a logical link backed by + * some form of a tunnel, e.g., GRE, MPLS, ODUk, OCH. + */ + TUNNEL, + + /** + * Signifies that this link is realized by fiber (either single channel or WDM). + */ + OPTICAL, + + /** + * Signifies that this link is a virtual link or a pseudo-wire. + */ + VIRTUAL + } + + /** + * Representation of the link state, which applies primarily only to + * configured durable links, i.e. those that need to remain present, + * but instead be marked as inactive. + */ + enum State { + /** + * Signifies that a link is currently active. + */ + ACTIVE, + + /** + * Signifies that a link is currently active. + */ + INACTIVE + } + + /** + * Returns the link source connection point. + * + * @return link source connection point + */ + ConnectPoint src(); + + /** + * Returns the link destination connection point. + * + * @return link destination connection point + */ + ConnectPoint dst(); + + /** + * Returns the link type. + * + * @return link type + */ + Type type(); + + /** + * Returns the link state. + * + * @return link state + */ + State state(); + + /** + * Indicates if the link is to be considered durable. + * + * @return true if the link is durable + */ + boolean isDurable(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/LinkKey.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/LinkKey.java new file mode 100644 index 00000000..9cb66492 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/LinkKey.java @@ -0,0 +1,110 @@ +/* + * Copyright 2014 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 static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Objects; + +import com.google.common.base.MoreObjects; + +// TODO Consider renaming. +// it's an identifier for a Link, but it's not ElementId, so not using LinkId. + +/** + * Immutable representation of a link identity. + */ +public final class LinkKey { + + private final ConnectPoint src; + private final ConnectPoint dst; + + /** + * Returns source connection point. + * + * @return source connection point + */ + public ConnectPoint src() { + return src; + } + + /** + * Returns destination connection point. + * + * @return destination connection point + */ + public ConnectPoint dst() { + return dst; + } + + /** + * Creates a link identifier with source and destination connection point. + * + * @param src source connection point + * @param dst destination connection point + */ + private LinkKey(ConnectPoint src, ConnectPoint dst) { + this.src = checkNotNull(src); + this.dst = checkNotNull(dst); + } + + /** + * Creates a link identifier with source and destination connection point. + * + * @param src source connection point + * @param dst destination connection point + * @return a link identifier + */ + public static LinkKey linkKey(ConnectPoint src, ConnectPoint dst) { + return new LinkKey(src, dst); + } + + /** + * Creates a link identifier for the specified link. + * + * @param link link descriptor + * @return a link identifier + */ + public static LinkKey linkKey(Link link) { + return new LinkKey(link.src(), link.dst()); + } + + @Override + public int hashCode() { + return Objects.hash(src, dst); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof LinkKey) { + final LinkKey other = (LinkKey) obj; + return Objects.equals(this.src, other.src) && + Objects.equals(this.dst, other.dst); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("src", src) + .add("dst", dst) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/MastershipRole.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/MastershipRole.java new file mode 100644 index 00000000..78f65864 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/MastershipRole.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014 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 relationship role of a controller instance to a device + * or a region of network environment. + */ +public enum MastershipRole { + + /** + * Represents a relationship where the controller instance is the master + * to a device or a region of network environment. + */ + MASTER, + + /** + * Represents a relationship where the controller instance is the standby, + * i.e. potential master to a device or a region of network environment. + */ + STANDBY, + + /** + * Represents that the controller instance is not eligible to be the master + * to a device or a region of network environment. + */ + NONE + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/MutableAnnotations.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/MutableAnnotations.java new file mode 100644 index 00000000..9b7f328e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/MutableAnnotations.java @@ -0,0 +1,40 @@ +/* + * 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; + +/** + * Represents an mutable set of simple key/value string annotations. + */ +public interface MutableAnnotations extends Annotations { + + /** + * Returns the value of the specified annotation. + * + * @param key annotation key + * @param value annotation value + * @return self + */ + MutableAnnotations set(String key, String value); + + /** + * Clears the specified keys or the all keys if none were specified. + * + * @param keys keys to be cleared + * @return self + */ + MutableAnnotations clear(String... keys); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/NetTools.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/NetTools.java new file mode 100644 index 00000000..fc561884 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/NetTools.java @@ -0,0 +1,37 @@ +/* + * 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; + +/** + * Networking domain tools. + */ +public final class NetTools { + + private NetTools() { + } + + /** + * Converts DPIDs of the form xx:xx:xx:xx:xx:xx:xx to OpenFlow provider + * device URIs. The is helpful for converting DPIDs coming from configuration + * or REST to URIs that the core understands. + * + * @param dpid the DPID string to convert + * @return the URI string for this device + */ + public static String dpidToUri(String dpid) { + return "of:" + dpid.replace(":", ""); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/NetworkResource.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/NetworkResource.java new file mode 100644 index 00000000..502208a0 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/NetworkResource.java @@ -0,0 +1,22 @@ +/* + * Copyright 2014 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 network resource, e.g. a link, lambda, MPLS tag. + */ +public interface NetworkResource { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchPort.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchPort.java new file mode 100644 index 00000000..eb956f2a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchPort.java @@ -0,0 +1,115 @@ +/* + * 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 java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Implementation of OCh port (Optical Channel). + * Also referred to as a line side port (L-port) or narrow band port. + * See ITU G.709 "Interfaces for the Optical Transport Network (OTN)" + */ +public class OchPort extends DefaultPort { + + private final OduSignalType signalType; + private final boolean isTunable; + private final OchSignal lambda; + + /** + * Creates an OCh port in the specified network element. + * + * @param element parent network element + * @param number port number + * @param isEnabled port enabled state + * @param signalType ODU signal type + * @param isTunable tunable wavelength capability + * @param lambda OCh signal + * @param annotations optional key/value annotations + */ + public OchPort(Element element, PortNumber number, boolean isEnabled, OduSignalType signalType, + boolean isTunable, OchSignal lambda, Annotations... annotations) { + super(element, number, isEnabled, Type.OCH, 0, annotations); + this.signalType = signalType; + this.isTunable = isTunable; + this.lambda = checkNotNull(lambda); + } + + /** + * Returns ODU signal type. + * + * @return ODU signal type + */ + public OduSignalType signalType() { + return signalType; + } + + /** + * Returns true if port is wavelength tunable. + * + * @return tunable wavelength capability + */ + public boolean isTunable() { + return isTunable; + } + + /** + * Returns OCh signal. + * + * @return OCh signal + */ + public OchSignal lambda() { + return lambda; + } + + @Override + public int hashCode() { + return Objects.hash(number(), isEnabled(), type(), signalType, isTunable, lambda, annotations()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof OchPort) { + final OchPort other = (OchPort) obj; + return Objects.equals(this.element().id(), other.element().id()) && + Objects.equals(this.number(), other.number()) && + Objects.equals(this.isEnabled(), other.isEnabled()) && + Objects.equals(this.signalType, other.signalType) && + Objects.equals(this.isTunable, other.isTunable) && + Objects.equals(this.lambda, other.lambda) && + Objects.equals(this.annotations(), other.annotations()); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("element", element().id()) + .add("number", number()) + .add("isEnabled", isEnabled()) + .add("type", type()) + .add("signalType", signalType) + .add("isTunable", isTunable) + .add("lambda", lambda) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchSignal.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchSignal.java new file mode 100644 index 00000000..5a5af34a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchSignal.java @@ -0,0 +1,176 @@ +/* + * 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 com.google.common.base.MoreObjects; +import org.onlab.util.Frequency; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Implementation of Lambda representing OCh (Optical Channel) Signal. + * + *

+ * See ITU G.709 "Interfaces for the Optical Transport Network (OTN)". + *

+ */ +public class OchSignal implements Lambda { + + public static final Frequency CENTER_FREQUENCY = Frequency.ofTHz(193.1); + public static final Frequency FLEX_GRID_SLOT = Frequency.ofGHz(12.5); + private static final GridType DEFAULT_OCH_GRIDTYPE = GridType.DWDM; + private static final ChannelSpacing DEFAULT_CHANNEL_SPACING = ChannelSpacing.CHL_50GHZ; + + + private final GridType gridType; + private final ChannelSpacing channelSpacing; + // Frequency = 193.1 THz + spacingMultiplier * channelSpacing + private final int spacingMultiplier; + // Slot width = slotGranularity * 12.5 GHz + private final int slotGranularity; + + /** + * Creates an instance with the specified arguments. + * It it recommended to use {@link Lambda#ochSignal(GridType, ChannelSpacing, int, int)} + * unless you want to use the concrete type, OchSignal, directly. + * + * @param gridType grid type + * @param channelSpacing channel spacing + * @param spacingMultiplier channel spacing multiplier + * @param slotGranularity slot width granularity + */ + public OchSignal(GridType gridType, ChannelSpacing channelSpacing, + int spacingMultiplier, int slotGranularity) { + this.gridType = checkNotNull(gridType); + this.channelSpacing = checkNotNull(channelSpacing); + // Negative values are permitted for spacingMultiplier + this.spacingMultiplier = spacingMultiplier; + checkArgument(slotGranularity > 0, "slotGranularity must be larger than 0, received %s", slotGranularity); + this.slotGranularity = slotGranularity; + } + + /** + * Create OCh signal from channel number. + * + * @param channel channel number + * @param maxFrequency maximum frequency + * @param grid grid spacing frequency + */ + public OchSignal(int channel, Frequency maxFrequency, Frequency grid) { + // Calculate center frequency + Frequency centerFrequency = maxFrequency.subtract(grid.multiply(channel - 1)); + + this.gridType = DEFAULT_OCH_GRIDTYPE; + this.channelSpacing = DEFAULT_CHANNEL_SPACING; + this.spacingMultiplier = (int) (centerFrequency.subtract(OchSignal.CENTER_FREQUENCY).asHz() / grid.asHz()); + this.slotGranularity = (int) Math.round((double) grid.asHz() / ChannelSpacing.CHL_12P5GHZ.frequency().asHz()); + } + + public OchSignal(Frequency centerFrequency, ChannelSpacing channelSpacing, int slotGranularity) { + this.gridType = DEFAULT_OCH_GRIDTYPE; + this.channelSpacing = channelSpacing; + this.spacingMultiplier = (int) Math.round((double) centerFrequency. + subtract(OchSignal.CENTER_FREQUENCY).asHz() / channelSpacing().frequency().asHz()); + this.slotGranularity = slotGranularity; + } + + /** + * Returns grid type. + * + * @return grid type + */ + public GridType gridType() { + return gridType; + } + + /** + * Returns channel spacing. + * + * @return channel spacing + */ + public ChannelSpacing channelSpacing() { + return channelSpacing; + } + + /** + * Returns spacing multiplier. + * + * @return spacing multiplier + */ + public int spacingMultiplier() { + return spacingMultiplier; + } + + /** + * Returns slow width granularity. + * + * @return slow width granularity + */ + public int slotGranularity() { + return slotGranularity; + } + + /** + * Returns central frequency in MHz. + * + * @return frequency in MHz + */ + public Frequency centralFrequency() { + return CENTER_FREQUENCY.add(channelSpacing().frequency().multiply(spacingMultiplier)); + } + + /** + * Returns slot width. + * + * @return slot width + */ + public Frequency slotWidth() { + return FLEX_GRID_SLOT.multiply(slotGranularity); + } + + @Override + public int hashCode() { + return Objects.hash(gridType, channelSpacing, spacingMultiplier, slotGranularity); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof OchSignal)) { + return false; + } + final OchSignal other = (OchSignal) obj; + return Objects.equals(this.gridType, other.gridType) + && Objects.equals(this.channelSpacing, other.channelSpacing) + && Objects.equals(this.spacingMultiplier, other.spacingMultiplier) + && Objects.equals(this.slotGranularity, other.slotGranularity); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("gridType", gridType) + .add("channelSpacing", channelSpacing) + .add("spacingMultiplier", spacingMultiplier) + .add("slotGranularity", slotGranularity) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchSignalType.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchSignalType.java new file mode 100644 index 00000000..9caf3f34 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OchSignalType.java @@ -0,0 +1,32 @@ +/* + * 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; + +/** + * Represents OCh (Optical Channel) signal type defined in + * Open Networking Foundation "Optical Transport Protocol Extensions Version 1.0". + */ +public enum OchSignalType { + /** + * Represents fixed grid. + */ + FIXED_GRID, + + /** + * Represents flex grid. + */ + FLEX_GRID +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/OduCltPort.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OduCltPort.java new file mode 100644 index 00000000..e5602f36 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OduCltPort.java @@ -0,0 +1,97 @@ +/* + * 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 java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of ODU client port (Optical channel Data Unit). + * Also referred to as a T-port or wide band port. + * See ITU G.709 "Interfaces for the Optical Transport Network (OTN)" + */ + +public class OduCltPort extends DefaultPort { + + public enum SignalType { + CLT_1GBE, + CLT_10GBE, + CLT_40GBE, + CLT_100GBE + } + + private final SignalType signalType; + + + /** + * Creates an ODU client port in the specified network element. + * + * @param element parent network element + * @param number port number + * @param isEnabled port enabled state + * @param signalType ODU client signal type + * @param annotations optional key/value annotations + */ + public OduCltPort(Element element, PortNumber number, boolean isEnabled, + SignalType signalType, Annotations... annotations) { + super(element, number, isEnabled, Type.ODUCLT, 0, annotations); + this.signalType = signalType; + } + + /** + * Returns ODU client signal type. + * + * @return ODU client signal type + */ + public SignalType signalType() { + return signalType; + } + + @Override + public int hashCode() { + return Objects.hash(number(), isEnabled(), type(), signalType, annotations()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof OduCltPort) { + final OduCltPort other = (OduCltPort) obj; + return Objects.equals(this.element().id(), other.element().id()) && + Objects.equals(this.number(), other.number()) && + Objects.equals(this.isEnabled(), other.isEnabled()) && + Objects.equals(this.signalType, other.signalType) && + Objects.equals(this.annotations(), other.annotations()); + } + return false; + } + + + @Override + public String toString() { + return toStringHelper(this) + .add("element", element().id()) + .add("number", number()) + .add("isEnabled", isEnabled()) + .add("type", type()) + .add("signalType", signalType) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/OduSignalType.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OduSignalType.java new file mode 100644 index 00000000..014c893b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OduSignalType.java @@ -0,0 +1,33 @@ +/* + * 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; + +/** + * Represents ODU (Optical channel Data Unit) signal type. + * + *

+ * See ITU G.709 "Interfaces for the Optical Transport Network (OTN)" and + * Open Networking Foundation "Optical Transport Protocol Extensions Version 1.0". + *

+ */ +public enum OduSignalType { + ODU0, + ODU1, + ODU2, + ODU2e, + ODU3, + ODU4 +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/OmsPort.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OmsPort.java new file mode 100644 index 00000000..753834b5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/OmsPort.java @@ -0,0 +1,131 @@ +/* + * 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.onlab.util.Frequency; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of OMS port (Optical Multiplexing Section). + * Also referred to as a WDM port or W-port. + * See ITU G.709 "Interfaces for the Optical Transport Network (OTN)" + * + * Assumes we only support fixed grid for now. + */ +public class OmsPort extends DefaultPort { + + private final Frequency minFrequency; // Minimum frequency + private final Frequency maxFrequency; // Maximum frequency + private final Frequency grid; // Grid spacing frequency + + + /** + * Creates an OMS port in the specified network element. + * + * @param element parent network element + * @param number port number + * @param isEnabled port enabled state + * @param minFrequency minimum frequency + * @param maxFrequency maximum frequency + * @param grid grid spacing frequency + * @param annotations optional key/value annotations + */ + public OmsPort(Element element, PortNumber number, boolean isEnabled, + Frequency minFrequency, Frequency maxFrequency, Frequency grid, Annotations... annotations) { + super(element, number, isEnabled, Type.OMS, 0, annotations); + this.minFrequency = minFrequency; + this.maxFrequency = maxFrequency; + this.grid = grid; + } + + /** + * Returns the total number of channels on the port. + * + * @return total number of channels + */ + public short totalChannels() { + Frequency diff = maxFrequency.subtract(minFrequency); + return (short) (diff.asHz() / (grid.asHz() + 1)); + } + + /** + * Returns the minimum frequency. + * + * @return minimum frequency + */ + public Frequency minFrequency() { + return minFrequency; + } + + /** + * Returns the maximum frequency. + * + * @return maximum frequency + */ + public Frequency maxFrequency() { + return maxFrequency; + } + + /** + * Returns the grid spacing frequency. + * + * @return grid spacing frequency + */ + public Frequency grid() { + return grid; + } + + @Override + public int hashCode() { + return Objects.hash(number(), isEnabled(), type(), + minFrequency, maxFrequency, grid, annotations()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof OmsPort) { + final OmsPort other = (OmsPort) obj; + return Objects.equals(this.element().id(), other.element().id()) && + Objects.equals(this.number(), other.number()) && + Objects.equals(this.isEnabled(), other.isEnabled()) && + Objects.equals(this.minFrequency, other.minFrequency) && + Objects.equals(this.maxFrequency, other.maxFrequency) && + Objects.equals(this.grid, other.grid) && + Objects.equals(this.annotations(), other.annotations()); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("element", element().id()) + .add("number", number()) + .add("isEnabled", isEnabled()) + .add("type", type()) + .add("minFrequency", minFrequency) + .add("maxFrequency", maxFrequency) + .add("grid", grid) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/Path.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Path.java new file mode 100644 index 00000000..c9c20c4c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Path.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014 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 java.util.List; + +/** + * 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 Path extends Link { + + /** + * Returns sequence of links comprising the path. + * + * @return list of links + */ + List links(); + + /** + * Returns the path cost as a unit-less value. + * + * @return unit-less path cost + */ + double cost(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/Port.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Port.java new file mode 100644 index 00000000..d70b1e17 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Port.java @@ -0,0 +1,100 @@ +/* + * Copyright 2014 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; + + +/** + * Abstraction of a network port. + */ +public interface Port extends Annotated { + + /** Represents coarse port type classification. */ + enum Type { + /** + * Signifies copper-based connectivity. + */ + COPPER, + + /** + * Signifies optical fiber-based connectivity. + */ + FIBER, + + /** + * Signifies optical fiber-based packet port. + */ + PACKET, + + /** + * Signifies optical fiber-based optical tributary port (called T-port). + * The signal from the client side will be formed into a ITU G.709 (OTN) frame. + */ + ODUCLT, + + /** + * Signifies optical fiber-based Line-side port (called L-port). + */ + OCH, + + /** + * Signifies optical fiber-based WDM port (called W-port). + * Optical Multiplexing Section (See ITU G.709). + */ + OMS, + + /** + * Signifies virtual port. + */ + VIRTUAL + } + + /** + * Returns the parent network element to which this port belongs. + * + * @return parent network element + */ + Element element(); + + /** + * Returns the port number. + * + * @return port number + */ + PortNumber number(); + + /** + * Indicates whether or not the port is currently up and active. + * + * @return true if the port is operational + */ + boolean isEnabled(); + + /** + * Returns the port type. + * + * @return port type + */ + Type type(); + + /** + * Returns the current port speed in Mbps. + * + * @return current port speed + */ + long portSpeed(); + + // TODO: more attributes? +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/PortNumber.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/PortNumber.java new file mode 100644 index 00000000..03e6dba9 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/PortNumber.java @@ -0,0 +1,182 @@ +/* + * Copyright 2014-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 com.google.common.primitives.UnsignedLongs; + +/** + * Representation of a port number. + */ +public final class PortNumber { + + public static final PortNumber P0 = portNumber(0); + + // TODO: revisit the max and the logical port value assignments + + private static final long MAX_NUMBER = (2L * Integer.MAX_VALUE) + 1; + + + static final long IN_PORT_NUMBER = -8L; + static final long TABLE_NUMBER = -7L; + static final long NORMAL_NUMBER = -6L; + static final long FLOOD_NUMBER = -5L; + static final long ALL_NUMBER = -4L; + static final long LOCAL_NUMBER = -2L; + static final long CONTROLLER_NUMBER = -3L; + + public static final PortNumber IN_PORT = new PortNumber(IN_PORT_NUMBER); + public static final PortNumber TABLE = new PortNumber(TABLE_NUMBER); + public static final PortNumber NORMAL = new PortNumber(NORMAL_NUMBER); + public static final PortNumber FLOOD = new PortNumber(FLOOD_NUMBER); + public static final PortNumber ALL = new PortNumber(ALL_NUMBER); + public static final PortNumber LOCAL = new PortNumber(LOCAL_NUMBER); + public static final PortNumber CONTROLLER = new PortNumber(CONTROLLER_NUMBER); + + private final long number; + private final String name; + private final boolean hasName; + + // Public creation is prohibited + private PortNumber(long number) { + this.number = number; + this.name = UnsignedLongs.toString(number); + this.hasName = false; + } + + private PortNumber(long number, String name) { + this.number = number; + this.name = name; + this.hasName = true; + } + + /** + * Returns the port number representing the specified long value. + * + * @param number port number as long value + * @return port number + */ + public static PortNumber portNumber(long number) { + return new PortNumber(number); + } + + /** + * Returns the port number representing the specified string value. + * + * @param string port number as string value + * @return port number + */ + public static PortNumber portNumber(String string) { + return new PortNumber(UnsignedLongs.decode(string)); + } + + /** + * Returns the port number representing the specified long value and name. + * + * @param number port number as long value + * @param name port name as string value + * @return port number + */ + public static PortNumber portNumber(long number, String name) { + return new PortNumber(number, name); + } + + /** + * Indicates whether or not this port number is a reserved logical one or + * whether it corresponds to a normal physical port of a device or NIC. + * + * @return true if logical port number + */ + public boolean isLogical() { + if (hasName) { + return false; + } else { + return (number < 0 || number > MAX_NUMBER); + } + } + + /** + * Returns the backing long value. + * + * @return port number as long + */ + public long toLong() { + return number; + } + + /** + * Returns the backing string value. + * + * @return port name as string value + */ + public String name() { + return name; + } + + /** + * Indicates whether this port number was created with a port name, + * or only with a number. + * + * @return true if port was created with name + */ + public boolean hasName() { + return hasName; + } + + private String decodeLogicalPort() { + if (number == CONTROLLER_NUMBER) { + return "CONTROLLER"; + } else if (number == LOCAL_NUMBER) { + return "LOCAL"; + } else if (number == ALL_NUMBER) { + return "ALL"; + } else if (number == FLOOD_NUMBER) { + return "FLOOD"; + } else if (number == NORMAL_NUMBER) { + return "NORMAL"; + } else if (number == TABLE_NUMBER) { + return "TABLE"; + } else if (number == IN_PORT_NUMBER) { + return "IN_PORT"; + } + return "UNKNOWN"; + } + + @Override + public String toString() { + if (!isLogical()) { + return name; + } else { + return decodeLogicalPort(); + } + } + + @Override + public int hashCode() { + return Long.hashCode(number); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof PortNumber) { + final PortNumber other = (PortNumber) obj; + return this.number == other.number; + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/Provided.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Provided.java new file mode 100644 index 00000000..daf85e75 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/Provided.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014 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; + +/** + * Abstraction of an entity supplied by a provider. + */ +public interface Provided { + + /** + * Returns the identifier of the provider which supplied the entity. + * + * @return provider identification + */ + ProviderId providerId(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/SparseAnnotations.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/SparseAnnotations.java new file mode 100644 index 00000000..97961b3a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/SparseAnnotations.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014 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 java.util.Set; + +/** + * Represents an set of sparse key/value string annotations capable of carrying + * annotation keys tagged for removal. + */ +public interface SparseAnnotations extends Annotations { + + /** + * {@inheritDoc} + *

+ * Note that this set includes keys for any attributes tagged for removal. + *

+ */ + @Override + Set keys(); + + /** + * Indicates whether the specified key has been tagged as removed. This is + * used for merging sparse annotation sets. + * + * @param key annotation key + * @return true if the previous annotation has been tagged for removal + */ + boolean isRemoved(String key); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java new file mode 100644 index 00000000..7f157e95 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeConfig.java @@ -0,0 +1,87 @@ +/* + * 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 java.util.Collection; +import java.util.List; +import java.util.Set; + +import org.onosproject.net.PortNumber; +import org.onosproject.net.device.PortDescription; +import org.onosproject.net.driver.HandlerBehaviour; + +/** + * Behaviour for handling various drivers for bridge configurations. + */ +public interface BridgeConfig extends HandlerBehaviour { + + /** + * Add a bridge. + * + * @param bridgeName bridge name + */ + void addBridge(BridgeName bridgeName); + + /** + * Remove a bridge. + * + * @param bridgeName bridge name + */ + void deleteBridge(BridgeName bridgeName); + + /** + * Remove a bridge. + * + * @return bridge collection + */ + Collection getBridges(); + + /** + * Add a logical/virtual port. + * + * @param port port number + */ + void addPort(PortDescription port); + + /** + * Delete a logical/virtual port. + * + * @param port port number + */ + void deletePort(PortDescription port); + + /** + * Delete a logical/virtual port. + * + * @return collection of port + */ + Collection getPorts(); + + /** + * Get a collection of port. + * + * @return portNumbers set of PortNumber + */ + Set getPortNumbers(); + + /** + * Get logical/virtual ports by ifaceIds. + * + * @param ifaceIds the ifaceid that needed + * @return list of PortNumber + */ + List getLocalPorts(Iterable ifaceIds); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeDescription.java new file mode 100644 index 00000000..3c1d5542 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeDescription.java @@ -0,0 +1,46 @@ +/* + * Copyright 2014-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.onosproject.net.Description; +import org.onosproject.net.DeviceId; + +/** + * The abstraction of bridge in OVSDB protocol. + */ +public interface BridgeDescription extends Description { + + /** + * Returns bridge name. + * + * @return bridge name + */ + BridgeName bridgeName(); + + /** + * Returns controller identifier that this bridge belongs to. + * + * @return controller identifier + */ + DeviceId cotrollerDeviceId(); + + /** + * Returns bridge identifier . + * + * @return bridge identifier + */ + DeviceId deviceId(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeName.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeName.java new file mode 100644 index 00000000..3f782954 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/BridgeName.java @@ -0,0 +1,78 @@ +/* + * Copyright 2014-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 java.util.Objects; + +import com.google.common.base.MoreObjects; + +/** + * Represents for a bridge name. + */ +public final class BridgeName { + + private final String name; + + // Public construction is prohibited + private BridgeName(String name) { + this.name = name; + } + + /** + * Creates a bridge name using the supplied string. + * + * @param name bridge name + * @return BridgeName + */ + public static BridgeName bridgeName(String name) { + return new BridgeName(name); + } + + /** + * Returns the bridge name string. + * + * @return name string + */ + public String name() { + return name; + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof BridgeName) { + final BridgeName that = (BridgeName) obj; + return this.getClass() == that.getClass() && + Objects.equals(this.name, that.name); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("name", name) + .toString(); + } + +} 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 new file mode 100644 index 00000000..bb8a788b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerConfig.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.net.behaviour; + +import java.util.List; + +/** + * Device behaviour to obtain and set controllers at the device. + */ +public interface ControllerConfig { + + //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 new file mode 100644 index 00000000..9ff808a9 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/ControllerInfo.java @@ -0,0 +1,38 @@ +/* + * 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.onlab.packet.IpAddress; + +/** + * Represents information for a device to connect to a controller. + */ +public class ControllerInfo { + + public final IpAddress ip; + public final int tcpPort; + + /** + * Information for contacting the controller. + * + * @param ip the ip address + * @param tcpPort the tcp port + */ + public ControllerInfo(IpAddress ip, int tcpPort) { + this.ip = ip; + this.tcpPort = tcpPort; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/DefaultBridgeDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/DefaultBridgeDescription.java new file mode 100644 index 00000000..6a6f670f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/DefaultBridgeDescription.java @@ -0,0 +1,87 @@ +/* + * Copyright 2014-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 java.util.Objects; + +import org.onosproject.net.AbstractDescription; +import org.onosproject.net.DeviceId; +import org.onosproject.net.SparseAnnotations; + +import com.google.common.base.MoreObjects; + +/** + * The default implementation of bridge. + */ +public final class DefaultBridgeDescription extends AbstractDescription + implements BridgeDescription { + + private final BridgeName name; + private final DeviceId deviceId; + private final DeviceId controllerId; + + public DefaultBridgeDescription(BridgeName name, DeviceId controllerId, + DeviceId deviceId, + SparseAnnotations... annotations) { + super(annotations); + this.name = name; + this.deviceId = deviceId; + this.controllerId = controllerId; + } + + @Override + public BridgeName bridgeName() { + return name; + } + + @Override + public DeviceId deviceId() { + return deviceId; + } + + @Override + public DeviceId cotrollerDeviceId() { + return controllerId; + } + + @Override + public int hashCode() { + return Objects.hash(name, deviceId, controllerId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultBridgeDescription) { + final DefaultBridgeDescription that = (DefaultBridgeDescription) obj; + return this.getClass() == that.getClass() + && Objects.equals(this.name, that.name) + && Objects.equals(this.deviceId, that.deviceId) + && Objects.equals(this.controllerId, that.controllerId); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()).add("name", name) + .add("deviceId", deviceId).add("controllerId", controllerId) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/DefaultNextGroup.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/DefaultNextGroup.java new file mode 100644 index 00000000..ef1f9de7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/DefaultNextGroup.java @@ -0,0 +1,33 @@ +/* + * 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; + +/** + * Default implementation of a next group. + */ +public class DefaultNextGroup implements NextGroup { + + private final byte[] data; + + public DefaultNextGroup(byte[] data) { + this.data = data; + } + + @Override + public byte[] data() { + return data; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/DefaultTunnelDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/DefaultTunnelDescription.java new file mode 100644 index 00000000..7554a3cb --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/DefaultTunnelDescription.java @@ -0,0 +1,87 @@ +/* + * 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.onosproject.net.AbstractDescription; +import org.onosproject.net.SparseAnnotations; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; + +/** + * Default implementation of immutable tunnel description entity. + */ +@Beta +public class DefaultTunnelDescription extends AbstractDescription + implements TunnelDescription { + + private final TunnelEndPoint src; + private final TunnelEndPoint dst; + private final Type type; + // which a tunnel match up + // tunnel producer + private final TunnelName tunnelName; // name of a tunnel + + /** + * Creates a tunnel description using the supplied information. + * + * @param src TunnelPoint source + * @param dst TunnelPoint destination + * @param type tunnel type + * @param tunnelName tunnel name + * @param annotations optional key/value annotations + */ + public DefaultTunnelDescription(TunnelEndPoint src, + TunnelEndPoint dst, Type type, + TunnelName tunnelName, + SparseAnnotations... annotations) { + super(annotations); + this.src = src; + this.dst = dst; + this.type = type; + this.tunnelName = tunnelName; + } + + @Override + public TunnelEndPoint src() { + return src; + } + + @Override + public TunnelEndPoint dst() { + return dst; + } + + @Override + public Type type() { + return type; + } + + @Override + public TunnelName tunnelName() { + return tunnelName; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("src", src()) + .add("dst", dst()) + .add("type", type()) + .add("tunnelName", tunnelName()) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/IpTunnelEndPoint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/IpTunnelEndPoint.java new file mode 100644 index 00000000..83ad4756 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/IpTunnelEndPoint.java @@ -0,0 +1,80 @@ +/* + * 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 java.util.Objects; + +import com.google.common.annotations.Beta; +import org.onlab.packet.IpAddress; + +import com.google.common.base.MoreObjects; + +/** + * Represent for a tunnel point using ip address. + */ +@Beta +public final class IpTunnelEndPoint implements TunnelEndPoint { + + private final IpAddress ip; + + /** + * Public construction is prohibited. + * @param ip ip address + */ + private IpTunnelEndPoint(IpAddress ip) { + this.ip = ip; + } + + /** + * Create a IP tunnel end point. + * @param ip IP address + * @return IpTunnelEndPoint + */ + public static IpTunnelEndPoint ipTunnelPoint(IpAddress ip) { + return new IpTunnelEndPoint(ip); + } + + /** + * Returns IP address. + * @return IP address + */ + public IpAddress ip() { + return ip; + } + + @Override + public int hashCode() { + return Objects.hash(ip); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof IpTunnelEndPoint) { + final IpTunnelEndPoint other = (IpTunnelEndPoint) obj; + return Objects.equals(this.ip, other.ip); + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()).add("ip", ip).toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/MplsQuery.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/MplsQuery.java new file mode 100644 index 00000000..0e9f466d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/MplsQuery.java @@ -0,0 +1,35 @@ +/* + * 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 com.google.common.annotations.Beta; +import org.onosproject.net.PortNumber; +import org.onosproject.net.driver.HandlerBehaviour; + +/** + * A HandlerBehaviour to check the capability of MPLS. + */ +@Beta +public interface MplsQuery extends HandlerBehaviour { + + /** + * Indicates if MPLS can be used at the port. + + * @param port port to be checked for the capability + * @return true if MPLS can be used at the port, false otherwise. + */ + boolean isEnabled(PortNumber port); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/NextGroup.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/NextGroup.java new file mode 100644 index 00000000..b5a3891c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/NextGroup.java @@ -0,0 +1,30 @@ +/* + * 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; + +/** + * Opaque data type for carrying group-like information. + * Only relevant to a pipeliner driver. + */ +public interface NextGroup { + + /** + * Serialized form of the next group. + * @return a byte array. + */ + byte[] data(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/Pipeliner.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/Pipeliner.java new file mode 100644 index 00000000..dcfc5883 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/Pipeliner.java @@ -0,0 +1,57 @@ +/* + * 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.onosproject.net.DeviceId; +import org.onosproject.net.driver.HandlerBehaviour; +import org.onosproject.net.flowobjective.FilteringObjective; +import org.onosproject.net.flowobjective.ForwardingObjective; +import org.onosproject.net.flowobjective.NextObjective; + +/** + * Behaviour for handling various pipelines. + */ +public interface Pipeliner extends HandlerBehaviour { + + /** + * Initializes the driver with context required for its operation. + * + * @param deviceId the deviceId + * @param context processing context + */ + void init(DeviceId deviceId, PipelinerContext context); + + /** + * Installs the filtering rules onto the device. + * + * @param filterObjective a filtering objective + */ + void filter(FilteringObjective filterObjective); + + /** + * Installs the forwarding rules onto the device. + * + * @param forwardObjective a forwarding objective + */ + void forward(ForwardingObjective forwardObjective); + + /** + * Installs the next hop elements into the device. + * + * @param nextObjective a next objectives + */ + void next(NextObjective nextObjective); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/PipelinerContext.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/PipelinerContext.java new file mode 100644 index 00000000..d0ca42b1 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/PipelinerContext.java @@ -0,0 +1,41 @@ +/* + * 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.onlab.osgi.ServiceDirectory; +import org.onosproject.net.flowobjective.FlowObjectiveStore; + +/** + * Processing context and supporting services for the pipeline behaviour. + */ +public interface PipelinerContext { + + /** + * Returns the service directory which can be used to obtain references + * to various supporting services. + * + * @return service directory + */ + ServiceDirectory directory(); + + /** + * Returns the Objective Store where data can be stored and retrieved. + * @return the flow objective store + */ + FlowObjectiveStore store(); + + // TODO: add means to store and access shared state +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/PortAdmin.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/PortAdmin.java new file mode 100644 index 00000000..141e27dc --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/PortAdmin.java @@ -0,0 +1,33 @@ +/* + * 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.onosproject.net.device.PortDescription; +import org.onosproject.net.driver.HandlerBehaviour; + +/** + * Means to administratively enable/disable a logical port at the device. + */ +public interface PortAdmin extends HandlerBehaviour { + + /** + * Enable/disable administratively a port. + * + * @param port a port description containing the desired port state + */ + void enable(PortDescription port); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/PortConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/PortConfig.java new file mode 100644 index 00000000..83dd99d8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/PortConfig.java @@ -0,0 +1,40 @@ +/* + * 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 com.google.common.primitives.UnsignedInteger; +import org.onosproject.net.device.PortDescription; +import org.onosproject.net.driver.HandlerBehaviour; + +/** + * Means to configure a logical port at the device. + */ +public interface PortConfig extends HandlerBehaviour { + + /** + * Apply QoS configuration on a device. + * @param port a port description + * @param queueId an unsigned integer + */ + void applyQoS(PortDescription port, UnsignedInteger queueId); + + /** + * Remove a QoS configuration. + * @param port a port description + */ + void removeQoS(PortDescription port); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/QueueConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/QueueConfig.java new file mode 100644 index 00000000..22f3ecb7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/QueueConfig.java @@ -0,0 +1,56 @@ +/* + * 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 com.google.common.primitives.UnsignedInteger; + +import java.util.Set; + +/** + * Means to alter a device's dataplane queues. + */ +public interface QueueConfig { + + /** + * Obtain all queues configured on a device. + * + * @return a list of queue descriptions + */ + Set getQueues(); + + /** + * Obtain a specific queue given a queue id. + * + * @param queueId an unsigned integer representing a queue id + * @return a queue description + */ + QueueInfo getQueue(UnsignedInteger queueId); + + /** + * Add a queue to a device. + * + * @param queue a queue description + */ + void addQueue(QueueInfo queue); + + /** + * Remove a queue from a device. + * + * @param queueId an unsigned integer + */ + void removeQueue(UnsignedInteger queueId); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/QueueInfo.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/QueueInfo.java new file mode 100644 index 00000000..25852b36 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/QueueInfo.java @@ -0,0 +1,56 @@ +/* + * 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 com.google.common.primitives.UnsignedInteger; + +/** + * Represents a dataplane queue. + */ +public class QueueInfo { + + public enum Type { + /** + * Supports burst and priority as well as min and max rates. + */ + FULL, + + /** + * Only support min and max rates. + */ + MINMAX + } + + private final UnsignedInteger queueId; + private final Type type; + private final long minRate; + private final long maxRate; + private final long burst; + private final long priority; + + public QueueInfo(UnsignedInteger queueId, Type type, long minRate, + long maxRate, long burst, long priority) { + this.queueId = queueId; + this.type = type; + this.minRate = minRate; + this.maxRate = maxRate; + this.burst = burst; + this.priority = priority; + } + + //TODO builder + // public static QueueInfoBuilder builder() {} +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelConfig.java new file mode 100644 index 00000000..7e79a57e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelConfig.java @@ -0,0 +1,55 @@ +/* + * 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 java.util.Collection; + +import org.onosproject.net.driver.HandlerBehaviour; + +/** + * Behaviour for handling various drivers for tunnel configuration. + */ +public interface TunnelConfig extends HandlerBehaviour { + + /** + * Creates a tunnel on this device. + * + * @param tunnel tunnel descriptor + */ + void createTunnel(TunnelDescription tunnel); + + /** + * Removes a tunnel on this device. + * + * @param tunnel tunnel descriptor + */ + void removeTunnel(TunnelDescription tunnel); + + /** + * Updates a tunnel on this device. + * + * @param tunnel tunnel descriptor + */ + void updateTunnel(TunnelDescription tunnel); + + /** + * Returns tunnels created on this device. + * + * @return collection of tunnels + */ + Collection getTunnels(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelDescription.java new file mode 100755 index 00000000..b2fb6996 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelDescription.java @@ -0,0 +1,86 @@ +/* + * 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.onosproject.net.Annotated; +import org.onosproject.net.Description; + +import com.google.common.annotations.Beta; + +/** + * Describes a tunnel. + */ +@Beta +public interface TunnelDescription extends Description, Annotated { + + /** + * Tunnel technology type. + */ + enum Type { + /** + * Signifies that this is a MPLS tunnel. + */ + MPLS, + /** + * Signifies that this is a L2 tunnel. + */ + VLAN, + /** + * Signifies that this is a DC L2 extension tunnel. + */ + VXLAN, + /** + * Signifies that this is a L3 tunnel. + */ + GRE, + /** + * Signifies that this is a L1 OTN tunnel. + */ + ODUK, + /** + * Signifies that this is a L0 OCH tunnel. + */ + OCH + } + + /** + * Returns the connection point source. + * + * @return tunnel source ConnectionPoint + */ + TunnelEndPoint src(); + + /** + * Returns the connection point destination. + * + * @return tunnel destination + */ + TunnelEndPoint dst(); + + /** + * Returns the tunnel type. + * + * @return tunnel type + */ + Type type(); + + /** + * Return the name of a tunnel. + * + * @return Tunnel Name + */ + TunnelName tunnelName(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelEndPoint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelEndPoint.java new file mode 100644 index 00000000..c354c38d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelEndPoint.java @@ -0,0 +1,28 @@ +/* + * 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 com.google.common.annotations.Beta; + +/** + * Represents for source end point or destination end point of a tunnel. Maybe a tunnel + * based on ConnectPoint, IpAddress, MacAddress and so on is built. + */ +@Beta +public interface TunnelEndPoint { + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelName.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelName.java new file mode 100644 index 00000000..9be26549 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/TunnelName.java @@ -0,0 +1,79 @@ +/* + * 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 com.google.common.annotations.Beta; + +import java.util.Objects; + +/** + * Represents for a unique tunnel name. TunnelId is generated by ONOS while + * TunnelName is given by producer. The consumer can borrow tunnels with + * TunnelId or TunnelName. + */ +@Beta +public final class TunnelName { + private final String str; + + // Default constructor for serialization + private TunnelName(String tunnelName) { + this.str = tunnelName; + } + + + /** + * Creates a tunnel name using the supplied URI string. + * + * @param tunnelName tunnel name string + * @return tunnel name object + */ + public static TunnelName tunnelName(String tunnelName) { + return new TunnelName(tunnelName); + } + + /** + * The string of tunnel name. + * + * @return the string of tunnel name + */ + public String value() { + return str; + } + + @Override + public int hashCode() { + return Objects.hash(str); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof TunnelName) { + final TunnelName that = (TunnelName) obj; + return this.getClass() == that.getClass() + && Objects.equals(this.str, that.str); + } + return false; + } + + @Override + public String toString() { + return str; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/VlanQuery.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/VlanQuery.java new file mode 100644 index 00000000..a1057c90 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/VlanQuery.java @@ -0,0 +1,35 @@ +/* + * 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 com.google.common.annotations.Beta; +import org.onosproject.net.PortNumber; +import org.onosproject.net.driver.HandlerBehaviour; + +/** + * A HandlerBehaviour to check the capability of VLAN. + */ +@Beta +public interface VlanQuery extends HandlerBehaviour { + + /** + * Indicates if VLAN can be used at the port. + * + * @param port port to be checked for the capability + * @return true if VLAN can be used at the port, false otherwise. + */ + boolean isEnabled(PortNumber port); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/package-info.java new file mode 100644 index 00000000..f0a9a5e5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/behaviour/package-info.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +/** + * Abstractions of various device configuration or device adaptation behaviours; + * counterpart to the device driver subsystem. + */ +package org.onosproject.net.behaviour; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/Config.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/Config.java new file mode 100644 index 00000000..5cdc0c12 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/Config.java @@ -0,0 +1,312 @@ +/* + * 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.config; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.annotations.Beta; +import com.google.common.collect.Lists; + +import java.util.Collection; +import java.util.List; +import java.util.function.Function; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Base abstraction of a configuration facade for a specific subject. Derived + * classes should keep all state in the specified JSON tree as that is the + * only state that will be distributed or persisted; this class is merely + * a facade for interacting with a particular facet of configuration on a + * given subject. + * + * @param type of subject + */ +@Beta +public abstract class Config { + + protected S subject; + protected String key; + + protected JsonNode node; + protected ObjectNode object; + protected ArrayNode array; + protected ObjectMapper mapper; + + protected ConfigApplyDelegate delegate; + + /** + * Initializes the configuration behaviour with necessary context. + * + * @param subject configuration subject + * @param key configuration key + * @param node JSON node where configuration data is stored + * @param mapper JSON object mapper + * @param delegate delegate context + */ + public void init(S subject, String key, JsonNode node, ObjectMapper mapper, + ConfigApplyDelegate delegate) { + this.subject = checkNotNull(subject); + this.key = key; + this.node = checkNotNull(node); + this.object = node instanceof ObjectNode ? (ObjectNode) node : null; + this.array = node instanceof ArrayNode ? (ArrayNode) node : null; + this.mapper = checkNotNull(mapper); + this.delegate = checkNotNull(delegate); + } + + /** + * Returns the specific subject to which this configuration pertains. + * + * @return configuration subject + */ + public S subject() { + return subject; + } + + /** + * Returns the configuration key. This is primarily aimed for use in + * composite JSON trees in external representations and has no bearing on + * the internal behaviours. + * + * @return configuration key + */ + public String key() { + return key; + } + + /** + * Returns the JSON node that contains the configuration data. + * + * @return JSON node backing the configuration + */ + public JsonNode node() { + return node; + } + + /** + * Applies any configuration changes made via this configuration. + */ + public void apply() { + delegate.onApply(this); + } + + + // Miscellaneous helpers for interacting with JSON + + /** + * Gets the specified property as a string. + * + * @param name property name + * @param defaultValue default value if property not set + * @return property value or default value + */ + protected String get(String name, String defaultValue) { + return object.path(name).asText(defaultValue); + } + + /** + * Sets the specified property as a string or clears it if null value given. + * + * @param name property name + * @param value new value or null to clear the property + * @return self + */ + protected Config setOrClear(String name, String value) { + if (value != null) { + object.put(name, value); + } else { + object.remove(name); + } + return this; + } + + /** + * Gets the specified property as a boolean. + * + * @param name property name + * @param defaultValue default value if property not set + * @return property value or default value + */ + protected boolean get(String name, boolean defaultValue) { + return object.path(name).asBoolean(defaultValue); + } + + /** + * Sets the specified property as a boolean or clears it if null value given. + * + * @param name property name + * @param value new value or null to clear the property + * @return self + */ + protected Config setOrClear(String name, Boolean value) { + if (value != null) { + object.put(name, value.booleanValue()); + } else { + object.remove(name); + } + return this; + } + + /** + * Gets the specified property as an integer. + * + * @param name property name + * @param defaultValue default value if property not set + * @return property value or default value + */ + protected int get(String name, int defaultValue) { + return object.path(name).asInt(defaultValue); + } + + /** + * Sets the specified property as an integer or clears it if null value given. + * + * @param name property name + * @param value new value or null to clear the property + * @return self + */ + protected Config setOrClear(String name, Integer value) { + if (value != null) { + object.put(name, value.intValue()); + } else { + object.remove(name); + } + return this; + } + + /** + * Gets the specified property as a long. + * + * @param name property name + * @param defaultValue default value if property not set + * @return property value or default value + */ + protected long get(String name, long defaultValue) { + return object.path(name).asLong(defaultValue); + } + + /** + * Sets the specified property as a long or clears it if null value given. + * + * @param name property name + * @param value new value or null to clear the property + * @return self + */ + protected Config setOrClear(String name, Long value) { + if (value != null) { + object.put(name, value.longValue()); + } else { + object.remove(name); + } + return this; + } + + /** + * Gets the specified property as a double. + * + * @param name property name + * @param defaultValue default value if property not set + * @return property value or default value + */ + protected double get(String name, double defaultValue) { + return object.path(name).asDouble(defaultValue); + } + + /** + * Sets the specified property as a double or clears it if null value given. + * + * @param name property name + * @param value new value or null to clear the property + * @return self + */ + protected Config setOrClear(String name, Double value) { + if (value != null) { + object.put(name, value.doubleValue()); + } else { + object.remove(name); + } + return this; + } + + /** + * Gets the specified property as an enum. + * + * @param name property name + * @param defaultValue default value if property not set + * @param enumClass the enum class + * @param type of enum + * @return property value or default value + */ + protected > E get(String name, E defaultValue, Class enumClass) { + return Enum.valueOf(enumClass, object.path(name).asText(defaultValue.toString())); + } + + /** + * Sets the specified property as a double or clears it if null value given. + * + * @param name property name + * @param value new value or null to clear the property + * @param type of enum + * @return self + */ + protected Config setOrClear(String name, E value) { + if (value != null) { + object.put(name, value.toString()); + } else { + object.remove(name); + } + return this; + } + + /** + * Gets the specified array property as a list of items. + * + * @param name property name + * @param function mapper from string to item + * @param type of item + * @return list of items + */ + protected List getList(String name, Function function) { + List list = Lists.newArrayList(); + ArrayNode arrayNode = (ArrayNode) object.path(name); + arrayNode.forEach(i -> list.add(function.apply(i.asText()))); + return list; + } + + /** + * Sets the specified property as an array of items in a given collection or + * clears it if null is given. + * + * @param name propertyName + * @param collection collection of items + * @param type of items + * @return self + */ + protected Config setOrClear(String name, Collection collection) { + if (collection == null) { + object.remove(name); + } else { + ArrayNode arrayNode = mapper.createArrayNode(); + collection.forEach(i -> arrayNode.add(i.toString())); + object.set(name, arrayNode); + } + return this; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/ConfigApplyDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/ConfigApplyDelegate.java new file mode 100644 index 00000000..1160a097 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/ConfigApplyDelegate.java @@ -0,0 +1,33 @@ +/* + * 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.config; + +import com.google.common.annotations.Beta; + +/** + * Delegate for notification when configuration changes have been applied. + */ +@Beta +public interface ConfigApplyDelegate { + + /** + * Processes changes applied to the specified configuration. + * + * @param config changed configuration + */ + void onApply(Config config); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/ConfigFactory.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/ConfigFactory.java new file mode 100644 index 00000000..25a34025 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/ConfigFactory.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.config; + + +import com.google.common.annotations.Beta; + +/** + * Base abstract factory for creating configurations for the specified subject type. + * + * @param type of subject + * @param type of configuration + */ +@Beta +public abstract class ConfigFactory> { + + private final SubjectFactory subjectFactory; + private final Class configClass; + private final String configKey; + private final boolean isList; + + /** + * Creates a new configuration factory for the specified class of subjects + * capable of generating the configurations of the specified class. The + * subject and configuration class keys are used merely as keys for use in + * composite JSON trees. + * + * @param subjectFactory subject factory + * @param configClass configuration class + * @param configKey configuration class key + */ + protected ConfigFactory(SubjectFactory subjectFactory, + Class configClass, String configKey) { + this(subjectFactory, configClass, configKey, false); + } + + /** + * Creates a new configuration factory for the specified class of subjects + * capable of generating the configurations of the specified class. The + * subject and configuration class keys are used merely as keys for use in + * composite JSON trees. + *

+ * Note that configurations backed by JSON array are not easily extensible + * at the top-level as they are inherently limited to holding an ordered + * list of items. + *

+ * + * @param subjectFactory subject factory + * @param configClass configuration class + * @param configKey configuration class key + * @param isList true to indicate backing by JSON array + */ + protected ConfigFactory(SubjectFactory subjectFactory, + Class configClass, String configKey, + boolean isList) { + this.subjectFactory = subjectFactory; + this.configClass = configClass; + this.configKey = configKey; + this.isList = isList; + } + + /** + * Returns the class of the subject to which this factory applies. + * + * @return subject type + */ + public SubjectFactory subjectFactory() { + return subjectFactory; + } + + /** + * Returns the class of the configuration which this factory generates. + * + * @return configuration type + */ + public Class configClass() { + return configClass; + } + + /** + * Returns the unique key (within subject class) of this configuration. + * This is primarily aimed for use in composite JSON trees in external + * representations and has no bearing on the internal behaviours. + * + * @return configuration key + */ + public String configKey() { + return configKey; + } + + /** + * Creates a new but uninitialized configuration. Framework will initialize + * the configuration via {@link Config#init} method. + * + * @return new uninitialized configuration + */ + public abstract C createConfig(); + + /** + * Indicates whether the configuration is a list and should be backed by + * a JSON array rather than JSON object. + * + * @return true if backed by JSON array + */ + public boolean isList() { + return isList; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/ConfigOperator.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/ConfigOperator.java new file mode 100644 index 00000000..505e8b3b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/ConfigOperator.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014-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.config; + +/** + * An interface signifying a class that implements network configuration + * information from multiple sources. There is a natural ordering to the + * precedence of information, depending on its source: + *
    + *
  1. Intents (from applications), which override
  2. + *
  3. Configs (from the network configuration subsystem), which override
  4. + *
  5. Descriptions (from southbound)
  6. + *
+ * i.e., for a field representing the same attribute, the value from a Config + * entity will be used over that from the Description. + */ +public interface ConfigOperator { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigEvent.java new file mode 100644 index 00000000..ee9ceadf --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigEvent.java @@ -0,0 +1,92 @@ +/* + * 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.config; + +import org.onosproject.event.AbstractEvent; + +/** + * Describes network configuration event. + */ +public class NetworkConfigEvent extends AbstractEvent { + + private final Class configClass; + + /** + * Type of network configuration events. + */ + public enum Type { + /** + * Signifies that a network configuration was registered. + */ + CONFIG_REGISTERED, + + /** + * Signifies that a network configuration was unregistered. + */ + CONFIG_UNREGISTERED, + + /** + * Signifies that network configuration was added. + */ + CONFIG_ADDED, + + /** + * Signifies that network configuration was updated. + */ + CONFIG_UPDATED, + + /** + * Signifies that network configuration was removed. + */ + CONFIG_REMOVED + } + + /** + * Creates an event of a given type and for the specified subject and the + * current time. + * + * @param type event type + * @param subject event subject + * @param configClass configuration class + */ + public NetworkConfigEvent(Type type, Object subject, Class configClass) { + super(type, subject); + this.configClass = configClass; + } + + /** + * Creates an event of a given type and for the specified subject and time. + * + * @param type device event type + * @param subject event subject + * @param configClass configuration class + * @param time occurrence time + */ + public NetworkConfigEvent(Type type, Object subject, Class configClass, long time) { + super(type, subject, time); + this.configClass = configClass; + } + + /** + * Returns the class of configuration that has been changed. + * + * @return configuration class + */ + public Class configClass() { + return configClass; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigListener.java new file mode 100644 index 00000000..73177755 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigListener.java @@ -0,0 +1,24 @@ +/* + * 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.config; + +import org.onosproject.event.EventListener; + +/** + * Entity capable of receiving network configuration related events. + */ +public interface NetworkConfigListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigRegistry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigRegistry.java new file mode 100644 index 00000000..b4937d74 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigRegistry.java @@ -0,0 +1,75 @@ +/* + * 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.config; + +import com.google.common.annotations.Beta; + +import java.util.Set; + +/** + * Service for tracking network configuration factories. It is the basis for + * extensibility to allow various core subsystems or apps to register their + * own configuration factories that permit use to inject additional meta + * information about how various parts of the network should be viewed and + * treated. + */ +@Beta +public interface NetworkConfigRegistry extends NetworkConfigService { + + /** + * Registers the specified configuration factory. + * + * @param configFactory configuration factory + */ + void registerConfigFactory(ConfigFactory configFactory); + + /** + * Unregisters the specified configuration factory. + * + * @param configFactory configuration factory + */ + void unregisterConfigFactory(ConfigFactory configFactory); + + /** + * Returns set of all registered configuration factories. + * + * @return set of config factories + */ + Set getConfigFactories(); + + /** + * Returns set of all configuration factories registered for the specified + * class of subject. + * + * @param subjectClass subject class + * @param type of subject + * @param type of configuration + * @return set of config factories + */ + > Set> getConfigFactories(Class subjectClass); + + /** + * Returns the configuration factory that produces the specified class of + * configurations. + * + * @param configClass configuration class + * @param type of subject + * @param type of configuration + * @return config factory + */ + > ConfigFactory getConfigFactory(Class configClass); + +} 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 new file mode 100644 index 00000000..c1eed980 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigService.java @@ -0,0 +1,146 @@ +/* + * 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.config; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.annotations.Beta; +import org.onosproject.event.ListenerService; + +import java.util.Set; + +/** + * Service for tracking network configurations which specify how the discovered + * network information should be interpreted and how the core or applications + * should act on or configure the network. + */ +@Beta +public interface NetworkConfigService + extends ListenerService { + + /** + * Returns the set of subject classes for which configuration may be + * available. + * + * @return set of subject classes + */ + Set getSubjectClasses(); + + /** + * Returns the subject factory with the specified key. + * + * @param subjectKey subject class key + * @return subject class + */ + SubjectFactory getSubjectFactory(String subjectKey); + + /** + * Returns the subject factory for the specified class. + * + * @param subjectClass subject class + * @return subject class key + */ + SubjectFactory getSubjectFactory(Class subjectClass); + + /** + * Returns the configuration class with the specified key. + * + * @param subjectKey subject class key + * @param configKey subject class name + * @return subject class + */ + Class getConfigClass(String subjectKey, String configKey); + + /** + * Returns the set of subjects for which some configuration is available. + * + * @param subjectClass subject class + * @param type of subject + * @return set of configured subjects + */ + Set getSubjects(Class subjectClass); + + /** + * Returns the set of subjects for which the specified configuration is + * available. + * + * @param subjectClass subject class + * @param configClass configuration class + * @param type of subject + * @param type of configuration + * @return set of configured subjects + */ + > Set getSubjects(Class subjectClass, Class configClass); + + /** + * Returns all configurations for the specified subject. + * + * @param subject configuration subject + * @param type of subject + * @return set of configurations + */ + Set> getConfigs(S subject); + + /** + * Returns the configuration for the specified subject and configuration + * class if one is available; null otherwise. + * + * @param subject configuration subject + * @param configClass configuration class + * @param type of subject + * @param type of configuration + * @return configuration or null if one is not available + */ + > C getConfig(S subject, Class configClass); + + /** + * Creates a new configuration for the specified subject and configuration + * class. If one already exists, it is simply returned. + * + * @param subject configuration subject + * @param configClass configuration class + * @param type of subject + * @param type of configuration + * @return configuration or null if one is not available + */ + > C addConfig(S subject, Class configClass); + + /** + * Applies configuration for the specified subject and configuration + * class using the raw JSON object. If configuration already exists, it + * will be updated. + * + * @param subject configuration subject + * @param configClass configuration class + * @param json raw JSON node containing the configuration data + * @param type of subject + * @param type of configuration + * @return configuration or null if one is not available + */ + > C applyConfig(S subject, Class configClass, + JsonNode json); + + /** + * Clears any configuration for the specified subject and configuration + * class. If one does not exist, this call has no effect. + * + * @param subject configuration subject + * @param configClass configuration class + * @param type of subject + * @param type of configuration + */ + > void removeConfig(S subject, Class configClass); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigStore.java new file mode 100644 index 00000000..9dd66e8d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigStore.java @@ -0,0 +1,130 @@ +/* + * 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.config; + +import com.fasterxml.jackson.databind.JsonNode; +import org.onosproject.store.Store; + +import java.util.Set; + +/** + * Mechanism for distributing and storing network configuration information. + */ +public interface NetworkConfigStore extends Store { + + /** + * Adds a new configuration factory. + * + * @param configFactory configuration factory to add + */ + void addConfigFactory(ConfigFactory configFactory); + + /** + * Removes a configuration factory. + * + * @param configFactory configuration factory to remove + */ + void removeConfigFactory(ConfigFactory configFactory); + + /** + * Returns the configuration factory for the specified configuration class. + * + * @param configClass configuration class + * @param type of subject + * @param type of configuration + * @return configuration factory or null + */ + > ConfigFactory getConfigFactory(Class configClass); + + /** + * Returns set of subjects of the specified class, which have some + * network configuration associated with them. + * + * @param subjectClass subject class + * @param type of subject + * @return set of subject + */ + Set getSubjects(Class subjectClass); + + /** + * Returns set of subjects of the specified class, which have the + * specified class of network configuration associated with them. + * + * @param subjectClass subject class + * @param configClass configuration class + * @param type of subject + * @param type of configuration + * @return set of subject + */ + > Set getSubjects(Class subjectClass, Class configClass); + + /** + * Returns set of configuration classes available for the specified subject. + * + * @param subject configuration subject + * @param type of subject + * @return set of configuration classes + */ + Set>> getConfigClasses(S subject); + + /** + * Get the configuration of the given class and for the specified subject. + * + * @param subject configuration subject + * @param configClass configuration class + * @param type of subject + * @param type of configuration + * @return configuration object + */ + > C getConfig(S subject, Class configClass); + + /** + * Creates a new configuration of the given class for the specified subject. + * + * @param subject configuration subject + * @param configClass configuration class + * @param type of subject + * @param type of configuration + * @return configuration object + */ + > C createConfig(S subject, Class configClass); + + /** + * Applies configuration for the specified subject and configuration + * class using the raw JSON object. If configuration already exists, it + * will be updated. + * + * @param subject configuration subject + * @param configClass configuration class + * @param json raw JSON node containing the configuration data + * @param type of subject + * @param type of configuration + * @return configuration object + */ + > C applyConfig(S subject, Class configClass, + JsonNode json); + + /** + * Clears the configuration of the given class for the specified subject. + * + * @param subject configuration subject + * @param configClass configuration class + * @param type of subject + * @param type of configuration + */ + > void clearConfig(S subject, Class configClass); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigStoreDelegate.java new file mode 100644 index 00000000..15d3d3e8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/NetworkConfigStoreDelegate.java @@ -0,0 +1,24 @@ +/* + * 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.config; + +import org.onosproject.store.StoreDelegate; + +/** + * Network configuration store delegate abstraction. + */ +public interface NetworkConfigStoreDelegate extends StoreDelegate { +} 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 new file mode 100644 index 00000000..cd2db344 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/SubjectFactory.java @@ -0,0 +1,75 @@ +/* + * 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.config; + + +import com.google.common.annotations.Beta; + +/** + * Base abstract factory for creating configuration subjects from their + * string key image. + * + * @param subject class + */ +@Beta +public abstract class SubjectFactory { + + private final Class subjectClass; + private final String subjectKey; + + /** + * Creates a new configuration factory for the specified class of subjects + * capable of generating the configurations of the specified class. The + * 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 + */ + protected SubjectFactory(Class subjectClass, String subjectKey) { + this.subjectClass = subjectClass; + this.subjectKey = subjectKey; + } + + /** + * Returns the class of the subject to which this factory applies. + * + * @return subject type + */ + public Class subjectClass() { + return subjectClass; + } + + /** + * Returns the unique key of this configuration subject class. + * This is primarily aimed for use in composite JSON trees in external + * representations and has no bearing on the internal behaviours. + * + * @return configuration key + */ + public String subjectKey() { + return subjectKey; + } + + /** + * Creates a configuration subject from its key image. + * + * @param subjectKey subject class key + * @return configuration subject + */ + public abstract S createSubject(String subjectKey); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/AllowedEntityConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/AllowedEntityConfig.java new file mode 100644 index 00000000..6e6663c4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/AllowedEntityConfig.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.config.basics; + +import org.onosproject.net.config.Config; + +/** + * Base abstraction for network entities for which admission into control + * domain can be selectively configured, e.g. devices, end-stations, links + */ +public abstract class AllowedEntityConfig extends Config { + + private static final String ALLOWED = "allowed"; + + /** + * Indicates whether the element is allowed for admission into the control + * domain. + * + * @return true if element is allowed + */ + public boolean isAllowed() { + return get(ALLOWED, true); + } + + /** + * Specifies whether the element is to be allowed for admission into the + * control domain. + * + * @param isAllowed true to allow; false to forbid; null to clear + * @return self + */ + public AllowedEntityConfig isAllowed(Boolean isAllowed) { + return (AllowedEntityConfig) setOrClear(ALLOWED, isAllowed); + } + +} 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 new file mode 100644 index 00000000..fd8bfa3e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicDeviceConfig.java @@ -0,0 +1,70 @@ +/* + * 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.config.basics; + +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; + +/** + * Basic configuration for network infrastructure devices. + */ +public class BasicDeviceConfig extends BasicElementConfig { + + public static final String TYPE = "type"; + public static final String DRIVER = "driver"; + + /** + * Returns the device type. + * + * @return device type override + */ + public Device.Type type() { + return get(TYPE, Device.Type.SWITCH, Device.Type.class); + } + + /** + * Sets the device type. + * + * @param type device type override + * @return self + */ + public BasicDeviceConfig type(Device.Type type) { + return (BasicDeviceConfig) setOrClear(TYPE, type); + } + + /** + * Returns the device driver name. + * + * @return driver name of null if not set + */ + public String driver() { + return get(DRIVER, subject.toString()); + } + + /** + * Sets the driver name. + * + * @param driverName new driver name; null to clear + * @return self + */ + public BasicElementConfig driver(String driverName) { + return (BasicElementConfig) setOrClear(DRIVER, driverName); + } + + // 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/BasicElementConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicElementConfig.java new file mode 100644 index 00000000..7b3248c9 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicElementConfig.java @@ -0,0 +1,130 @@ +/* + * 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.config.basics; + +/** + * Basic configuration for network elements, e.g. devices, hosts. Such elements + * can have a friendly name, geo-coordinates, logical rack coordinates and + * an owner entity. + */ +public abstract class BasicElementConfig extends AllowedEntityConfig { + + public static final String NAME = "name"; + + public static final String LATITUDE = "latitude"; + public static final String LONGITUDE = "longitude"; + + public static final String RACK_ADDRESS = "rackAddress"; + public static final String OWNER = "owner"; + + protected static final double DEFAULT_COORD = -1.0; + + /** + * Returns friendly label for the element. + * + * @return friendly label or element id itself if not set + */ + public String name() { + return get(NAME, subject.toString()); + } + + /** + * Sets friendly label for the element. + * + * @param name new friendly label; null to clear + * @return self + */ + public BasicElementConfig name(String name) { + return (BasicElementConfig) setOrClear(NAME, name); + } + + /** + * Returns element latitude. + * + * @return element latitude; -1 if not set + */ + public double latitude() { + return get(LATITUDE, DEFAULT_COORD); + } + + /** + * Sets the element latitude. + * + * @param latitude new latitude; null to clear + * @return self + */ + public BasicElementConfig latitude(Double latitude) { + return (BasicElementConfig) setOrClear(LATITUDE, latitude); + } + + /** + * Returns element latitude. + * + * @return element latitude; -1 if not set + */ + public double longitude() { + return get(LONGITUDE, DEFAULT_COORD); + } + + /** + * Sets the element longitude. + * + * @param longitude new longitude; null to clear + * @return self + */ + public BasicElementConfig longitude(Double longitude) { + return (BasicElementConfig) setOrClear(LONGITUDE, longitude); + } + + /** + * Returns the element rack address. + * + * @return rack address; null if not set + */ + public String rackAddress() { + return get(RACK_ADDRESS, null); + } + + /** + * Sets element rack address. + * + * @param address new rack address; null to clear + * @return self + */ + public BasicElementConfig rackAddress(String address) { + return (BasicElementConfig) setOrClear(RACK_ADDRESS, address); + } + + /** + * Returns owner of the element. + * + * @return owner or null if not set + */ + public String owner() { + return get(OWNER, null); + } + + /** + * Sets the owner of the element. + * + * @param owner new owner; null to clear + * @return self + */ + public BasicElementConfig owner(String owner) { + return (BasicElementConfig) setOrClear(OWNER, owner); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicHostConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicHostConfig.java new file mode 100644 index 00000000..2fe2b2c0 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicHostConfig.java @@ -0,0 +1,27 @@ +/* + * 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.config.basics; + +import org.onosproject.net.HostId; + +/** + * Basic configuration for network end-station hosts. + */ +public class BasicHostConfig extends BasicElementConfig { + + // TODO: determine what aspects of configuration to add for hosts + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicLinkConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicLinkConfig.java new file mode 100644 index 00000000..b6068ee7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/BasicLinkConfig.java @@ -0,0 +1,90 @@ +/* + * 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.config.basics; + +import org.onosproject.net.Link; +import org.onosproject.net.LinkKey; + +import java.time.Duration; + +/** + * Basic configuration for network infrastructure link. + */ +public class BasicLinkConfig extends AllowedEntityConfig { + + public static final String TYPE = "type"; + public static final String LATENCY = "latency"; + public static final String BANDWIDTH = "bandwidth"; + + /** + * Returns the link type. + * + * @return link type override + */ + public Link.Type type() { + return get(TYPE, Link.Type.DIRECT, Link.Type.class); + } + + /** + * Sets the link type. + * + * @param type link type override + * @return self + */ + public BasicLinkConfig type(Link.Type type) { + return (BasicLinkConfig) setOrClear(TYPE, type); + } + + /** + * Returns link latency in terms of nanos. + * + * @return link latency; -1 if not set + */ + public Duration latency() { + return Duration.ofNanos(get(LATENCY, -1)); + } + + /** + * Sets the link latency. + * + * @param latency new latency; null to clear + * @return self + */ + public BasicLinkConfig latency(Duration latency) { + Long nanos = latency == null ? null : latency.toNanos(); + return (BasicLinkConfig) setOrClear(LATENCY, nanos); + } + + /** + * Returns link bandwidth in terms of Mbps. + * + * @return link bandwidth; -1 if not set + */ + public long bandwidth() { + return get(BANDWIDTH, -1); + } + + /** + * Sets the link bandwidth. + * + * @param bandwidth new bandwidth; null to clear + * @return self + */ + public BasicLinkConfig bandwidth(Long bandwidth) { + return (BasicLinkConfig) setOrClear(BANDWIDTH, bandwidth); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/OpticalPortConfig.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/OpticalPortConfig.java new file mode 100644 index 00000000..b06c4228 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/OpticalPortConfig.java @@ -0,0 +1,175 @@ +package org.onosproject.net.config.basics; + +import java.util.Optional; + +import org.onosproject.net.config.Config; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Port; + +import com.fasterxml.jackson.databind.JsonNode; + + +/** + * Configurations for an optical port on a device. + */ +public class OpticalPortConfig extends Config { + // optical type {OMS, OCH, ODUClt, fiber} + public static final String TYPE = "type"; + + // port name. "name" is the alphanumeric name of the port, but "port" refers + // to the port number used as a name string (i.e., for ports without + // alphanumeric names). + public static final String NAME = "name"; + public static final String PORT = "port"; + public static final String STATIC_PORT = "staticPort"; + public static final String STATIC_LAMBDA = "staticLambda"; + + // **Linc-OE : remove if it's not needed after all.** + public static final String SPEED = "speed"; + + /** + * Returns the Enum value representing the type of port. + * + * @return the port type, or null if invalid or unset + */ + public Port.Type type() { + JsonNode type = object.path(TYPE); + if (type.isMissingNode()) { + return null; + } + return Port.Type.valueOf(type.asText()); + } + + /** + * Returns the port name associated with this port configuration. The Name + * is an alphanumeric string. + * + * @return the name of this port, else, an empty string + */ + public String name() { + return getStringValue(NAME); + } + + /** + * Returns a stringified representation of the port number, configured in + * some port types without an alphanumeric name as the port name. + * + * @return A string representation of the port number + */ + public String numberName() { + return getStringValue(PORT); + } + + /** + * Returns the string-representation of name of the output port. This is + * usually an OMS port for an OCH input ports, or an OCH port for ODU input + * ports. + * + * @return the name of this port, else, an empty string + */ + public String staticPort() { + return getStringValue(STATIC_PORT); + } + + private String getStringValue(String field) { + JsonNode name = object.path(field); + return name.isMissingNode() ? "" : name.asText(); + } + + /** + * Returns the output lambda configured for this port. The lambda value is + * expressed as a frequency value. If the port type doesn't have a notion of + * lambdas, this returns an empty Optional. + * + * @return an Optional that may contain a frequency value. + */ + public Optional staticLambda() { + JsonNode sl = object.path(STATIC_LAMBDA); + if (sl.isMissingNode()) { + return Optional.empty(); + } + return Optional.of(sl.asLong()); + } + + /** + * Returns the port speed configured for this port. If the port doesn't have + * a notion of speed, this returns an empty Optional. + * + * @return a port speed value whose default is 0. + */ + public Optional speed() { + JsonNode s = object.path(SPEED); + if (s.isMissingNode()) { + return Optional.empty(); + } + return Optional.of(s.asInt()); + } + + /** + * Sets the port type, or updates it if it's already set. A null argument removes + * this field. + * + * @param type the port type + * @return this OpticalPortConfig instance + */ + public OpticalPortConfig portType(Port.Type type) { + // if unspecified, ideally fall back on FIBER or PACKET. + String pt = (type == null) ? null : type.toString(); + return (OpticalPortConfig) setOrClear(TYPE, pt); + } + + /** + * Sets the port name, or updates it if already set. A null argument removes + * this field. + * + * @param name the port's name + * @return this OpticalPortConfig instance + */ + public OpticalPortConfig portName(String name) { + return (OpticalPortConfig) setOrClear(NAME, name); + } + + /** + * Sets the port name from port number, or updates it if already set. A null + * argument removes this field. + * + * @param name the port number, to be used as name + * @return this OpticalPortConfig instance + */ + public OpticalPortConfig portNumberName(Long name) { + return (OpticalPortConfig) setOrClear(PORT, name); + } + + /** + * Sets the output port name, or updates it if already set. A null argument + * removes this field. + * + * @param name the output port's name + * @return this OpticalPortConfig instance + */ + public OpticalPortConfig staticPort(String name) { + return (OpticalPortConfig) setOrClear(STATIC_PORT, name); + } + + /** + * Sets the output lambda index, or updates it if already set. A null argument + * removes this field. + * + * @param index the output lambda + * @return this OpticalPortConfig instance + */ + public OpticalPortConfig staticLambda(Long index) { + return (OpticalPortConfig) setOrClear(STATIC_LAMBDA, index); + } + + /** + * Sets the port speed, or updates it if already set. A null argument + * removes this field. + * + * @param bw the port bandwidth + * @return this OpticalPortConfig instance + */ + public OpticalPortConfig speed(Integer bw) { + return (OpticalPortConfig) setOrClear(SPEED, bw); + } +} 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 new file mode 100644 index 00000000..884f2e20 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/SubjectFactories.java @@ -0,0 +1,93 @@ +/* + * 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.config.basics; + +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.HostId; +import org.onosproject.net.LinkKey; +import org.onosproject.net.config.SubjectFactory; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Set of subject factories for potential configuration subjects. + */ +public final class SubjectFactories { + + // Construction forbidden + private SubjectFactories() { + } + + // Required for resolving application identifiers + private static CoreService coreService; + + public static final SubjectFactory APP_SUBJECT_FACTORY = + new SubjectFactory(ApplicationId.class, "apps") { + @Override + public ApplicationId createSubject(String key) { + return coreService.registerApplication(key); + } + }; + + public static final SubjectFactory DEVICE_SUBJECT_FACTORY = + new SubjectFactory(DeviceId.class, "devices") { + @Override + public DeviceId createSubject(String key) { + return DeviceId.deviceId(key); + } + }; + + public static final SubjectFactory CONNECT_POINT_SUBJECT_FACTORY = + new SubjectFactory(ConnectPoint.class, "ports") { + @Override + public ConnectPoint createSubject(String key) { + return ConnectPoint.deviceConnectPoint(key); + } + }; + + public static final SubjectFactory HOST_SUBJECT_FACTORY = + new SubjectFactory(HostId.class, "hosts") { + @Override + public HostId createSubject(String key) { + return HostId.hostId(key); + } + }; + + public static final SubjectFactory LINK_SUBJECT_FACTORY = + new SubjectFactory(LinkKey.class, "links") { + @Override + public LinkKey createSubject(String key) { + String[] cps = key.split("-"); + checkArgument(cps.length == 2, "Incorrect link key format: %s", key); + return LinkKey.linkKey(ConnectPoint.deviceConnectPoint(cps[0]), + ConnectPoint.deviceConnectPoint(cps[1])); + } + }; + + /** + * Provides reference to the core service, which is required for + * application subject factory. + * + * @param service core service reference + */ + public static void setCoreService(CoreService service) { + coreService = service; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/package-info.java new file mode 100644 index 00000000..4d0f27e9 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/basics/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. + */ + +/** + * Various basic builtin network configurations. + */ +package org.onosproject.net.config.basics; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/package-info.java new file mode 100644 index 00000000..f300717a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/config/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. + */ + +/** + * Subsystem for tracking network environment configuration. + */ +package org.onosproject.net.config; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DefaultDeviceDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DefaultDeviceDescription.java new file mode 100644 index 00000000..3a8c8c1f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DefaultDeviceDescription.java @@ -0,0 +1,145 @@ +/* + * Copyright 2014-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.device; + +import org.onosproject.net.AbstractDescription; +import org.onosproject.net.SparseAnnotations; +import org.onlab.packet.ChassisId; + +import java.net.URI; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.Device.Type; + +/** + * Default implementation of immutable device description entity. + */ +public class DefaultDeviceDescription extends AbstractDescription + implements DeviceDescription { + private final URI uri; + private final Type type; + private final String manufacturer; + private final String hwVersion; + private final String swVersion; + private final String serialNumber; + private final ChassisId chassisId; + + /** + * Creates a device description using the supplied information. + * + * @param uri device URI + * @param type device type + * @param manufacturer device manufacturer + * @param hwVersion device HW version + * @param swVersion device SW version + * @param serialNumber device serial number + * @param chassis chassis id + * @param annotations optional key/value annotations map + */ + public DefaultDeviceDescription(URI uri, Type type, String manufacturer, + String hwVersion, String swVersion, + String serialNumber, ChassisId chassis, + SparseAnnotations... annotations) { + super(annotations); + this.uri = checkNotNull(uri, "Device URI cannot be null"); + this.type = checkNotNull(type, "Device type cannot be null"); + this.manufacturer = manufacturer; + this.hwVersion = hwVersion; + this.swVersion = swVersion; + this.serialNumber = serialNumber; + this.chassisId = chassis; + } + + /** + * Creates a device description using the supplied information. + * @param base DeviceDescription to basic information + * @param annotations Annotations to use. + */ + public DefaultDeviceDescription(DeviceDescription base, + SparseAnnotations... annotations) { + this(base.deviceURI(), base.type(), base.manufacturer(), + base.hwVersion(), base.swVersion(), base.serialNumber(), + base.chassisId(), annotations); + } + + /** + * Creates a device description using the supplied information. + * @param base DeviceDescription to basic information (except for type) + * @param type device type + * @param annotations Annotations to use. + */ + public DefaultDeviceDescription(DeviceDescription base, Type type, SparseAnnotations... annotations) { + this(base.deviceURI(), type, base.manufacturer(), + base.hwVersion(), base.swVersion(), base.serialNumber(), + base.chassisId(), annotations); + } + + @Override + public URI deviceURI() { + return uri; + } + + @Override + public Type type() { + return type; + } + + @Override + public String manufacturer() { + return manufacturer; + } + + @Override + public String hwVersion() { + return hwVersion; + } + + @Override + public String swVersion() { + return swVersion; + } + + @Override + public String serialNumber() { + return serialNumber; + } + + @Override + public ChassisId chassisId() { + return chassisId; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("uri", uri).add("type", type).add("mfr", manufacturer) + .add("hw", hwVersion).add("sw", swVersion) + .add("serial", serialNumber) + .toString(); + } + + // default constructor for serialization + private DefaultDeviceDescription() { + this.uri = null; + this.type = null; + this.manufacturer = null; + this.hwVersion = null; + this.swVersion = null; + this.serialNumber = null; + this.chassisId = null; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DefaultPortDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DefaultPortDescription.java new file mode 100644 index 00000000..572d201c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DefaultPortDescription.java @@ -0,0 +1,120 @@ +/* + * Copyright 2014 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.device; + +import com.google.common.base.MoreObjects; +import org.onosproject.net.AbstractDescription; +import org.onosproject.net.PortNumber; +import org.onosproject.net.SparseAnnotations; + +import static org.onosproject.net.Port.Type; + +/** + * Default implementation of immutable port description. + */ +public class DefaultPortDescription extends AbstractDescription + implements PortDescription { + + private static final long DEFAULT_SPEED = 1_000; + + private final PortNumber number; + private final boolean isEnabled; + private final Type type; + private final long portSpeed; + + /** + * Creates a port description using the supplied information. + * + * @param number port number + * @param isEnabled port enabled state + * @param annotations optional key/value annotations map + */ + public DefaultPortDescription(PortNumber number, boolean isEnabled, + SparseAnnotations... annotations) { + this(number, isEnabled, Type.COPPER, DEFAULT_SPEED, annotations); + } + + /** + * Creates a port description using the supplied information. + * + * @param number port number + * @param isEnabled port enabled state + * @param type port type + * @param portSpeed port speed in Mbps + * @param annotations optional key/value annotations map + */ + public DefaultPortDescription(PortNumber number, boolean isEnabled, + Type type, long portSpeed, + SparseAnnotations...annotations) { + super(annotations); + this.number = number; + this.isEnabled = isEnabled; + this.type = type; + this.portSpeed = portSpeed; + } + + // Default constructor for serialization + private DefaultPortDescription() { + this.number = null; + this.isEnabled = false; + this.portSpeed = DEFAULT_SPEED; + this.type = Type.COPPER; + } + + /** + * Creates a port description using the supplied information. + * + * @param base PortDescription to get basic information from + * @param annotations optional key/value annotations map + */ + public DefaultPortDescription(PortDescription base, + SparseAnnotations annotations) { + this(base.portNumber(), base.isEnabled(), base.type(), base.portSpeed(), + annotations); + } + + @Override + public PortNumber portNumber() { + return number; + } + + @Override + public boolean isEnabled() { + return isEnabled; + } + + @Override + public Type type() { + return type; + } + + @Override + public long portSpeed() { + return portSpeed; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("number", number) + .add("isEnabled", isEnabled) + .add("type", type) + .add("portSpeed", portSpeed) + .add("annotations", annotations()) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DefaultPortStatistics.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DefaultPortStatistics.java new file mode 100644 index 00000000..540a945f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DefaultPortStatistics.java @@ -0,0 +1,346 @@ +/* + * 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.device; + +import org.onosproject.net.DeviceId; + +/** + * Default implementation of immutable port statistics. + */ +public final class DefaultPortStatistics implements PortStatistics { + + private final DeviceId deviceId; + private final int port; + private final long packetsReceived; + private final long packetsSent; + private final long bytesReceived; + private final long bytesSent; + private final long packetsRxDropped; + private final long packetsTxDropped; + private final long packetsRxErrors; + private final long packetsTxErrors; + private final long durationSec; + private final long durationNano; + + private DefaultPortStatistics(DeviceId deviceId, + int port, + long packetsReceived, + long packetsSent, + long bytesReceived, + long bytesSent, + long packetsRxDropped, + long packetsTxDropped, + long packetsRxErrors, + long packetsTxErrors, + long durationSec, + long durationNano) { + this.deviceId = deviceId; + this.port = port; + this.packetsReceived = packetsReceived; + this.packetsSent = packetsSent; + this.bytesReceived = bytesReceived; + this.bytesSent = bytesSent; + this.packetsRxDropped = packetsRxDropped; + this.packetsTxDropped = packetsTxDropped; + this.packetsRxErrors = packetsRxErrors; + this.packetsTxErrors = packetsTxErrors; + this.durationSec = durationSec; + this.durationNano = durationNano; + } + + // Constructor for serializer + private DefaultPortStatistics() { + this.deviceId = null; + this.port = 0; + this.packetsReceived = 0; + this.packetsSent = 0; + this.bytesReceived = 0; + this.bytesSent = 0; + this.packetsRxDropped = 0; + this.packetsTxDropped = 0; + this.packetsRxErrors = 0; + this.packetsTxErrors = 0; + this.durationSec = 0; + this.durationNano = 0; + } + + /** + * Creates a builder for DefaultPortStatistics object. + * + * @return builder object for DefaultPortStatistics object + */ + public static DefaultPortStatistics.Builder builder() { + return new Builder(); + } + + @Override + public int port() { + return this.port; + } + + @Override + public long packetsReceived() { + return this.packetsReceived; + } + + @Override + public long packetsSent() { + return this.packetsSent; + } + + @Override + public long bytesReceived() { + return this.bytesReceived; + } + + @Override + public long bytesSent() { + return this.bytesSent; + } + + @Override + public long packetsRxDropped() { + return this.packetsRxDropped; + } + + @Override + public long packetsTxDropped() { + return this.packetsTxDropped; + } + + @Override + public long packetsRxErrors() { + return this.packetsRxErrors; + } + + @Override + public long packetsTxErrors() { + return this.packetsTxErrors; + } + + @Override + public long durationSec() { + return this.durationSec; + } + + @Override + public long durationNano() { + return this.durationNano; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("device: " + deviceId + ", "); + + sb.append("port: " + this.port + ", "); + sb.append("pktRx: " + this.packetsReceived + ", "); + sb.append("pktTx: " + this.packetsSent + ", "); + sb.append("byteRx: " + this.bytesReceived + ", "); + sb.append("byteTx: " + this.bytesSent + ", "); + sb.append("pktRxErr: " + this.packetsRxErrors + ", "); + sb.append("pktTxErr: " + this.packetsTxErrors + ", "); + sb.append("pktRxDrp: " + this.packetsRxDropped + ", "); + sb.append("pktTxDrp: " + this.packetsTxDropped); + + return sb.toString(); + } + + public static final class Builder { + + DeviceId deviceId; + int port; + long packetsReceived; + long packetsSent; + long bytesReceived; + long bytesSent; + long packetsRxDropped; + long packetsTxDropped; + long packetsRxErrors; + long packetsTxErrors; + long durationSec; + long durationNano; + + private Builder() { + + } + + /** + * Sets port number. + * + * @param port port number + * @return builder object + */ + public Builder setPort(int port) { + this.port = port; + + return this; + } + + /** + * Sets the device identifier. + * + * @param deviceId device identifier + * @return builder object + */ + public Builder setDeviceId(DeviceId deviceId) { + this.deviceId = deviceId; + + return this; + } + + /** + * Sets the number of packet received. + * + * @param packets number of packets received + * @return builder object + */ + public Builder setPacketsReceived(long packets) { + packetsReceived = packets; + + return this; + } + + /** + * Sets the number of packets sent. + * + * @param packets number of packets sent + * @return builder object + */ + public Builder setPacketsSent(long packets) { + packetsSent = packets; + + return this; + } + + /** + * Sets the number of received bytes. + * + * @param bytes number of received bytes. + * @return builder object + */ + public Builder setBytesReceived(long bytes) { + bytesReceived = bytes; + + return this; + } + + /** + * Sets the number of sent bytes. + * + * @param bytes number of sent bytes + * @return builder object + */ + public Builder setBytesSent(long bytes) { + bytesSent = bytes; + + return this; + } + + /** + * Sets the number of packets dropped by RX. + * + * @param packets number of packets dropped by RX + * @return builder object + */ + public Builder setPacketsRxDropped(long packets) { + packetsRxDropped = packets; + + return this; + } + + /** + * Sets the number of packets dropped by TX. + * + * @param packets number of packets + * @return builder object + */ + public Builder setPacketsTxDropped(long packets) { + packetsTxDropped = packets; + + return this; + } + + /** + * Sets the number of receive errors. + * + * @param packets number of receive errors + * @return builder object + */ + public Builder setPacketsRxErrors(long packets) { + packetsRxErrors = packets; + + return this; + } + + /** + * Sets the number of transmit errors. + * + * @param packets number of transmit errors + * @return builder object + */ + public Builder setPacketsTxErrors(long packets) { + packetsTxErrors = packets; + + return this; + } + + /** + * Sets the time port has been alive in seconds. + * + * @param sec time port has been alive in seconds + * @return builder object + */ + public Builder setDurationSec(long sec) { + durationSec = sec; + + return this; + } + + /** + * Sets the time port has been alive in nano seconds. + * + * @param nano time port has been alive in nano seconds + * @return builder object + */ + public Builder setDurationNano(long nano) { + durationNano = nano; + + return this; + } + + /** + * Creates a PortStatistics object. + * + * @return DefaultPortStatistics object + */ + public DefaultPortStatistics build() { + return new DefaultPortStatistics( + deviceId, + port, + packetsReceived, + packetsSent, + bytesReceived, + bytesSent, + packetsRxDropped, + packetsTxDropped, + packetsRxErrors, + packetsTxErrors, + durationSec, + durationNano); + } + + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceAdminService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceAdminService.java new file mode 100644 index 00000000..500b6359 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceAdminService.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014-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.device; + +import org.onosproject.net.DeviceId; + +/** + * Service for administering the inventory of infrastructure devices. + */ +public interface DeviceAdminService extends DeviceService { + + /** + * Removes the device with the specified identifier. + * + * @param deviceId device identifier + */ + void removeDevice(DeviceId deviceId); + + // TODO: add ability to administratively suspend/resume device + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceClockService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceClockService.java new file mode 100644 index 00000000..5391999a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceClockService.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014 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.device; + +import org.onosproject.net.DeviceId; +import org.onosproject.store.Timestamp; + +/** + * Interface for a logical clock service that vends per device timestamps. + */ +public interface DeviceClockService { + + /** + * Checks if this service can issue Timestamp for specified device. + * + * @param deviceId device identifier. + * @return true if timestamp can be issued for specified device + */ + boolean isTimestampAvailable(DeviceId deviceId); + + /** + * Returns a new timestamp for the specified deviceId. + * + * @param deviceId device identifier. + * @return timestamp. + */ + Timestamp getTimestamp(DeviceId deviceId); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceDescription.java new file mode 100644 index 00000000..64b84b5a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceDescription.java @@ -0,0 +1,80 @@ +/* + * Copyright 2014-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.device; + +import org.onosproject.net.Description; +import org.onosproject.net.Device; +import org.onlab.packet.ChassisId; + +import java.net.URI; + +/** + * Carrier of immutable information about a device. + */ +public interface DeviceDescription extends Description { + + /** + * Protocol/provider specific URI that can be used to encode the identity + * information required to communicate with the device externally, e.g. + * datapath ID. + * + * @return provider specific URI for the device + */ + URI deviceURI(); + + /** + * Returns the type of the infrastructure device. + * + * @return type of the device + */ + Device.Type type(); + + /** + * Returns the device manufacturer name. + * + * @return manufacturer name + */ + String manufacturer(); + + /** + * Returns the device hardware version. + * + * @return hardware version + */ + String hwVersion(); + + /** + * Returns the device software version. + * + * @return software version + */ + String swVersion(); + + /** + * Returns the device serial number. + * + * @return serial number + */ + String serialNumber(); + + /** + * Returns a device chassis id. + * + * @return chassis id + */ + ChassisId chassisId(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceEvent.java new file mode 100644 index 00000000..18ab046f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceEvent.java @@ -0,0 +1,141 @@ +/* + * Copyright 2014-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.device; + +import org.joda.time.LocalDateTime; +import org.onosproject.event.AbstractEvent; +import org.onosproject.net.Device; +import org.onosproject.net.Port; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Describes infrastructure device event. + */ +public class DeviceEvent extends AbstractEvent { + + private final Port port; + + /** + * Type of device events. + */ + public enum Type { + /** + * Signifies that a new device has been detected. + */ + DEVICE_ADDED, + + /** + * Signifies that some device attributes have changed; excludes + * availability changes. + */ + DEVICE_UPDATED, + + /** + * Signifies that a device has been removed. + */ + DEVICE_REMOVED, + + /** + * Signifies that a device has been administratively suspended. + */ + DEVICE_SUSPENDED, + + /** + * Signifies that a device has come online or has gone offline. + */ + DEVICE_AVAILABILITY_CHANGED, + + /** + * Signifies that a port has been added. + */ + PORT_ADDED, + + /** + * Signifies that a port has been updated. + */ + PORT_UPDATED, + + /** + * Signifies that a port has been removed. + */ + PORT_REMOVED, + + /** + * Signifies that port statistics has been updated. + */ + PORT_STATS_UPDATED + } + + /** + * Creates an event of a given type and for the specified device and the + * current time. + * + * @param type device event type + * @param device event device subject + */ + public DeviceEvent(Type type, Device device) { + this(type, device, null); + } + + /** + * Creates an event of a given type and for the specified device, port + * and the current time. + * + * @param type device event type + * @param device event device subject + * @param port optional port subject + */ + public DeviceEvent(Type type, Device device, Port port) { + super(type, device); + this.port = port; + } + + /** + * Creates an event of a given type and for the specified device and time. + * + * @param type device event type + * @param device event device subject + * @param port optional port subject + * @param time occurrence time + */ + public DeviceEvent(Type type, Device device, Port port, long time) { + super(type, device, time); + this.port = port; + } + + /** + * Returns the port subject. + * + * @return port subject or null if the event is not port specific. + */ + public Port port() { + return port; + } + + @Override + public String toString() { + if (port == null) { + return super.toString(); + } + return toStringHelper(this) + .add("time", new LocalDateTime(time())) + .add("type", type()) + .add("subject", subject()) + .add("port", port) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceListener.java new file mode 100644 index 00000000..c9809b81 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceListener.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.device; + +import org.onosproject.event.EventListener; + +/** + * Entity capable of receiving infrastructure device related events. + */ +public interface DeviceListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceProvider.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceProvider.java new file mode 100644 index 00000000..d8adbb0e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceProvider.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014 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.device; + +import org.onosproject.net.DeviceId; +import org.onosproject.net.MastershipRole; +import org.onosproject.net.provider.Provider; + +/** + * Abstraction of a device information provider. + */ +public interface DeviceProvider extends Provider { + + // TODO: consider how dirty the triggerProbe gets; if it costs too much, let's drop it + + /** + * Triggers an asynchronous probe of the specified device, intended to + * determine whether the device is present or not. An indirect result of this + * should be invocation of + * {@link org.onosproject.net.device.DeviceProviderService#deviceConnected} )} or + * {@link org.onosproject.net.device.DeviceProviderService#deviceDisconnected} + * at some later point in time. + * + * @param deviceId ID of device to be probed + */ + void triggerProbe(DeviceId deviceId); + + /** + * Notifies the provider of a mastership role change for the specified + * device as decided by the core. + * + * @param deviceId device identifier + * @param newRole newly determined mastership role + */ + void roleChanged(DeviceId deviceId, MastershipRole newRole); + + /** + * Checks the reachability (connectivity) of a device from this provider. + * + * @param deviceId device identifier + * @return true if reachable, false otherwise + */ + boolean isReachable(DeviceId deviceId); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceProviderRegistry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceProviderRegistry.java new file mode 100644 index 00000000..a7ab7e36 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceProviderRegistry.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 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.device; + +import org.onosproject.net.provider.ProviderRegistry; + +/** + * Abstraction of a device provider registry. + */ +public interface DeviceProviderRegistry + extends ProviderRegistry { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceProviderService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceProviderService.java new file mode 100644 index 00000000..e266df09 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceProviderService.java @@ -0,0 +1,82 @@ +/* + * Copyright 2014-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.device; + +import org.onosproject.net.DeviceId; +import org.onosproject.net.MastershipRole; +import org.onosproject.net.provider.ProviderService; + +import java.util.Collection; +import java.util.List; + +/** + * Service through which device providers can inject device information into + * the core. + */ +public interface DeviceProviderService extends ProviderService { + + // TODO: define suspend and remove actions on the mezzanine administrative API + + /** + * Signals the core that a device has connected or has been detected somehow. + * + * @param deviceId device identifier + * @param deviceDescription information about network device + */ + void deviceConnected(DeviceId deviceId, DeviceDescription deviceDescription); + + /** + * Signals the core that a device has disconnected or is no longer reachable. + * + * @param deviceId identity of the device to be removed + */ + void deviceDisconnected(DeviceId deviceId); + + /** + * Sends information about all ports of a device. It is up to the core to + * determine what has changed. + * + * @param deviceId identity of the device + * @param portDescriptions list of device ports + */ + void updatePorts(DeviceId deviceId, List portDescriptions); + + /** + * Used to notify the core about port status change of a single port. + * + * @param deviceId identity of the device + * @param portDescription description of the port that changed + */ + void portStatusChanged(DeviceId deviceId, PortDescription portDescription); + + /** + * Notifies the core about the result of a RoleRequest sent to a device. + * + * @param deviceId identity of the device + * @param requested mastership role that was requested by the node + * @param response mastership role the switch accepted + */ + void receivedRoleReply(DeviceId deviceId, MastershipRole requested, MastershipRole response); + + /** + * Sends statistics about all ports of a device. + * + * @param deviceId identity of the device + * @param portStatistics list of device port statistics + */ + void updatePortStatistics(DeviceId deviceId, Collection portStatistics); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceService.java new file mode 100644 index 00000000..f4671fb4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceService.java @@ -0,0 +1,132 @@ +/* + * Copyright 2014-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.device; + +import org.onosproject.event.ListenerService; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.MastershipRole; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; + +import java.util.List; + +/** + * Service for interacting with the inventory of infrastructure devices. + */ +public interface DeviceService + extends ListenerService { + + /** + * Returns the number of infrastructure devices known to the system. + * + * @return number of infrastructure devices + */ + int getDeviceCount(); + + /** + * Returns a collection of the currently known infrastructure + * devices. + * + * @return collection of devices + */ + Iterable getDevices(); + + /** + * Returns a collection of the currently known infrastructure + * devices by device type. + * + * @param type device type + * @return collection of devices + */ + Iterable getDevices(Device.Type type); + + /** + * Returns an iterable collection of all devices + * currently available to the system. + * + * @return device collection + */ + Iterable getAvailableDevices(); + + /** + * Returns an iterable collection of all devices currently available to the system by device type. + * + * @param type device type + * @return device collection + */ + Iterable getAvailableDevices(Device.Type type); + + /** + * Returns the device with the specified identifier. + * + * @param deviceId device identifier + * @return device or null if one with the given identifier is not known + */ + Device getDevice(DeviceId deviceId); + + /** + * Returns the current mastership role for the specified device. + * + * @param deviceId device identifier + * @return designated mastership role + */ + //XXX do we want this method here when MastershipService already does? + MastershipRole getRole(DeviceId deviceId); + + + /** + * Returns the list of ports associated with the device. + * + * @param deviceId device identifier + * @return list of ports + */ + List getPorts(DeviceId deviceId); + + /** + * Returns the list of port statistics associated with the device. + * + * @param deviceId device identifier + * @return list of port statistics + */ + List getPortStatistics(DeviceId deviceId); + + /** + * Returns the list of port delta statistics associated with the device. + * + * @param deviceId device identifier + * @return list of port statistics + */ + List getPortDeltaStatistics(DeviceId deviceId); + + /** + * Returns the port with the specified number and hosted by the given device. + * + * @param deviceId device identifier + * @param portNumber port number + * @return device port + */ + Port getPort(DeviceId deviceId, PortNumber portNumber); + + /** + * Indicates whether or not the device is presently online and available. + * + * @param deviceId device identifier + * @return true if the device is available + */ + boolean isAvailable(DeviceId deviceId); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceStore.java new file mode 100644 index 00000000..851b9709 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceStore.java @@ -0,0 +1,170 @@ +/* + * Copyright 2014-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.device; + +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.store.Store; + +import java.util.Collection; +import java.util.List; + +/** + * Manages inventory of infrastructure devices; not intended for direct use. + */ +public interface DeviceStore extends Store { + + /** + * Returns the number of devices known to the system. + * + * @return number of devices + */ + int getDeviceCount(); + + /** + * Returns an iterable collection of all devices known to the system. + * + * @return device collection + */ + Iterable getDevices(); + + /** + * Returns an iterable collection of all devices currently available to the system. + * + * @return device collection + */ + Iterable getAvailableDevices(); + + + + /** + * Returns the device with the specified identifier. + * + * @param deviceId device identifier + * @return device + */ + Device getDevice(DeviceId deviceId); + + /** + * Creates a new infrastructure device, or updates an existing one using + * the supplied device description. + * + * @param providerId provider identifier + * @param deviceId device identifier + * @param deviceDescription device description + * @return ready to send event describing what occurred; null if no change + */ + DeviceEvent createOrUpdateDevice(ProviderId providerId, DeviceId deviceId, + DeviceDescription deviceDescription); + + // TODO: We may need to enforce that ancillary cannot interfere this state + /** + * Removes the specified infrastructure device. + * + * @param deviceId device identifier + * @return ready to send event describing what occurred; null if no change + */ + DeviceEvent markOffline(DeviceId deviceId); + + /** + * Updates the ports of the specified infrastructure device using the given + * list of port descriptions. The list is assumed to be comprehensive. + * + * @param providerId provider identifier + * @param deviceId device identifier + * @param portDescriptions list of port descriptions + * @return ready to send events describing what occurred; empty list if no change + */ + List updatePorts(ProviderId providerId, DeviceId deviceId, + List portDescriptions); + + /** + * Updates the port status of the specified infrastructure device using the + * given port description. + * + * @param providerId provider identifier + * @param deviceId device identifier + * @param portDescription port description + * @return ready to send event describing what occurred; null if no change + */ + DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, + PortDescription portDescription); + + /** + * Returns the list of ports that belong to the specified device. + * + * @param deviceId device identifier + * @return list of device ports + */ + List getPorts(DeviceId deviceId); + + /** + * Updates the port statistics of the specified device using the give port + * statistics. + * + * @param providerId provider identifier + * @param deviceId device identifier + * @param portStats list of port statistics + * @return ready to send event describing what occurred; + */ + DeviceEvent updatePortStatistics(ProviderId providerId, DeviceId deviceId, + Collection portStats); + + /** + * Returns the list of port statistics of the specified device. + * + * @param deviceId device identifier + * @return list of port statistics of all ports of the device + */ + List getPortStatistics(DeviceId deviceId); + + /** + * Returns the list of delta port statistics of the specified device. + * + * @param deviceId device identifier + * @return list of delta port statistics of all ports of the device + */ + List getPortDeltaStatistics(DeviceId deviceId); + + /** + * Returns the specified device port. + * + * @param deviceId device identifier + * @param portNumber port number + * @return device port + */ + Port getPort(DeviceId deviceId, PortNumber portNumber); + + /** + * Indicates whether the specified device is available/online. + * + * @param deviceId device identifier + * @return true if device is available + */ + boolean isAvailable(DeviceId deviceId); + + /** + * Administratively removes the specified device from the store. + * + * @param deviceId device to be removed + * @return null if no such device, or was forwarded to remove master + */ + DeviceEvent removeDevice(DeviceId deviceId); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceStoreDelegate.java new file mode 100644 index 00000000..1a4fc67d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/DeviceStoreDelegate.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.device; + +import org.onosproject.store.StoreDelegate; + +/** + * Infrastructure device store delegate abstraction. + */ +public interface DeviceStoreDelegate extends StoreDelegate { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.java new file mode 100644 index 00000000..c3a7f415 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/OchPortDescription.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.net.device; + +import com.google.common.base.MoreObjects; +import org.onosproject.net.OchSignal; +import org.onosproject.net.OduSignalType; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.SparseAnnotations; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default implementation of immutable OCh port description. + */ +public class OchPortDescription extends DefaultPortDescription { + + private final OduSignalType signalType; + private final boolean isTunable; + private final OchSignal lambda; + + /** + * Creates OCH port description based on the supplied information. + * + * @param number port number + * @param isEnabled port enabled state + * @param signalType ODU signal type + * @param isTunable tunable wavelength capability + * @param lambda OCh signal + * @param annotations optional key/value annotations map + */ + public OchPortDescription(PortNumber number, boolean isEnabled, OduSignalType signalType, + boolean isTunable, OchSignal lambda, SparseAnnotations... annotations) { + super(number, isEnabled, Port.Type.OCH, 0, annotations); + this.signalType = signalType; + this.isTunable = isTunable; + this.lambda = checkNotNull(lambda); + } + + /** + * Creates OCH port description based on the supplied information. + * + * @param base PortDescription to get basic information from + * @param signalType ODU signal type + * @param isTunable tunable wavelength capability + * @param lambda OCh signal + * @param annotations optional key/value annotations map + */ + public OchPortDescription(PortDescription base, OduSignalType signalType, boolean isTunable, + OchSignal lambda, SparseAnnotations annotations) { + super(base, annotations); + this.signalType = signalType; + this.isTunable = isTunable; + this.lambda = checkNotNull(lambda); + } + + /** + * Returns ODU signal type. + * + * @return ODU signal type + */ + public OduSignalType signalType() { + return signalType; + } + + /** + * Returns true if port is wavelength tunable. + * + * @return tunable wavelength capability + */ + public boolean isTunable() { + return isTunable; + } + + /** + * Returns OCh signal. + * + * @return OCh signal + */ + public OchSignal lambda() { + return lambda; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("number", portNumber()) + .add("isEnabled", isEnabled()) + .add("type", type()) + .add("signalType", signalType) + .add("isTunable", isTunable) + .add("lambda", lambda) + .add("annotations", annotations()) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/OduCltPortDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/OduCltPortDescription.java new file mode 100644 index 00000000..eee7de2d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/OduCltPortDescription.java @@ -0,0 +1,77 @@ +/* + * 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.device; + +import com.google.common.base.MoreObjects; +import org.onosproject.net.OduCltPort; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.SparseAnnotations; + +/** + * Default implementation of immutable ODU client port description. + */ +public class OduCltPortDescription extends DefaultPortDescription { + + private final OduCltPort.SignalType signalType; + + /** + * Creates ODU client port description based on the supplied information. + * + * @param number port number + * @param isEnabled port enabled state + * @param signalType ODU client signal type + * @param annotations optional key/value annotations map + */ + public OduCltPortDescription(PortNumber number, boolean isEnabled, OduCltPort.SignalType signalType, + SparseAnnotations... annotations) { + super(number, isEnabled, Port.Type.ODUCLT, 0, annotations); + this.signalType = signalType; + } + + /** + * Creates ODU client port description based on the supplied information. + * + * @param base PortDescription to get basic information from + * @param signalType ODU client signal type + * @param annotations optional key/value annotations map + */ + public OduCltPortDescription(PortDescription base, OduCltPort.SignalType signalType, + SparseAnnotations annotations) { + super(base, annotations); + this.signalType = signalType; + } + + /** + * Returns ODU client signal type. + * + * @return ODU client signal type + */ + public OduCltPort.SignalType signalType() { + return signalType; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("number", portNumber()) + .add("isEnabled", isEnabled()) + .add("type", type()) + .add("signalType", signalType) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/OmsPortDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/OmsPortDescription.java new file mode 100644 index 00000000..131314a3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/OmsPortDescription.java @@ -0,0 +1,109 @@ +/* + * 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.device; + +import com.google.common.base.MoreObjects; +import org.onlab.util.Frequency; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.SparseAnnotations; + +/** + * Default implementation of immutable OMS port description. + */ +public class OmsPortDescription extends DefaultPortDescription { + + private final Frequency minFrequency; + private final Frequency maxFrequency; + private final Frequency grid; + + /** + * Creates OMS port description based on the supplied information. + * + * @param number port number + * @param isEnabled port enabled state + * @param minFrequency minimum frequency + * @param maxFrequency maximum frequency + * @param grid grid spacing frequency + * @param annotations optional key/value annotations map + */ + public OmsPortDescription(PortNumber number, boolean isEnabled, Frequency minFrequency, Frequency maxFrequency, + Frequency grid, SparseAnnotations... annotations) { + super(number, isEnabled, Port.Type.OMS, 0, annotations); + this.minFrequency = minFrequency; + this.maxFrequency = maxFrequency; + this.grid = grid; + } + + /** + * Creates OMS port description based on the supplied information. + * + * @param base PortDescription to get basic information from + * @param minFrequency minimum frequency + * @param maxFrequency maximum frequency + * @param grid grid spacing frequency + * @param annotations optional key/value annotations map + */ + public OmsPortDescription(PortDescription base, Frequency minFrequency, Frequency maxFrequency, + Frequency grid, SparseAnnotations annotations) { + super(base, annotations); + this.minFrequency = minFrequency; + this.maxFrequency = maxFrequency; + this.grid = grid; + } + + /** + * Returns minimum frequency. + * + * @return minimum frequency + */ + public Frequency minFrequency() { + return minFrequency; + } + + /** + * Returns maximum frequency. + * + * @return maximum frequency + */ + public Frequency maxFrequency() { + return maxFrequency; + } + + /** + * Returns grid spacing frequency. + * + * @return grid spacing frequency + */ + public Frequency grid() { + return grid; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("number", portNumber()) + .add("isEnabled", isEnabled()) + .add("type", type()) + .add("minFrequency", minFrequency) + .add("maxFrequency", maxFrequency) + .add("grid", grid) + .add("annotations", annotations()) + .toString(); + } + +} + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/PortDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/PortDescription.java new file mode 100644 index 00000000..3ed3efce --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/PortDescription.java @@ -0,0 +1,56 @@ +/* + * Copyright 2014 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.device; + +import org.onosproject.net.Description; +import org.onosproject.net.PortNumber; + +import static org.onosproject.net.Port.Type; + +/** + * Information about a port. + */ +public interface PortDescription extends Description { + + /** + * Returns the port number. + * + * @return port number + */ + PortNumber portNumber(); + + /** + * Indicates whether or not the port is up and active. + * + * @return true if the port is active and has carrier signal + */ + boolean isEnabled(); + + /** + * Returns the port type. + * + * @return port type + */ + Type type(); + + /** + * Returns the current port speed in Mbps. + * + * @return current port speed + */ + long portSpeed(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/PortStatistics.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/PortStatistics.java new file mode 100644 index 00000000..201bd7b6 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/PortStatistics.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.device; + +/** + * Statistics of a port. + */ +public interface PortStatistics { + + /** + * Returns the port number. + * + * @return port number + */ + int port(); + + /** + * Returns the number of packets received. + * + * @return the number of packets received + */ + long packetsReceived(); + + /** + * Returns the number of packets sent. + * + * @return the number of packets sent + */ + long packetsSent(); + + /** + * Returns the bytes received. + * + * @return the bytes received + */ + long bytesReceived(); + + /** + * Returns the bytes sent. + * + * @return the bytes sent + */ + long bytesSent(); + + /** + * Returns the number of packets dropped by RX. + * + * @return the number of packets dropped by RX + */ + long packetsRxDropped(); + + /** + * Returns the number of packets dropped by TX. + * + * @return the number of packets dropped by TX + */ + long packetsTxDropped(); + + /** + * Returns the number of transmit errors. + * + * @return the number of transmit errors + */ + long packetsRxErrors(); + + /** + * Returns the number of receive errors. + * + * @return the number of receive error + */ + long packetsTxErrors(); + + /** + * Returns the time port has been alive in seconds. + * + * @return the time port has been alive in seconds + */ + long durationSec(); + + /** + * Returns the time port has been alive in nano seconds. + * + * @return the time port has been alive in nano seconds + */ + long durationNano(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/package-info.java new file mode 100644 index 00000000..4ee64dcf --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/device/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Infrastructure device model & related services API definitions. + */ +package org.onosproject.net.device; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/AbstractBehaviour.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/AbstractBehaviour.java new file mode 100644 index 00000000..784e6c55 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/AbstractBehaviour.java @@ -0,0 +1,37 @@ +/* + * 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.driver; + +import static com.google.common.base.Preconditions.checkState; + +/** + * Base implementation of device driver behaviour. + */ +public class AbstractBehaviour implements Behaviour { + + private DriverData data; + + @Override + public DriverData data() { + return data; + } + + @Override + public void setData(DriverData data) { + checkState(this.data == null, "Driver data already set"); + this.data = data; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/AbstractHandlerBehaviour.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/AbstractHandlerBehaviour.java new file mode 100644 index 00000000..66b21ffe --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/AbstractHandlerBehaviour.java @@ -0,0 +1,38 @@ +/* + * 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.driver; + +import static com.google.common.base.Preconditions.checkState; + +/** + * Base implementation of device driver handler behaviour. + */ +public class AbstractHandlerBehaviour + extends AbstractBehaviour implements HandlerBehaviour { + + private DriverHandler handler; + + @Override + public DriverHandler handler() { + return handler; + } + + @Override + public void setHandler(DriverHandler handler) { + checkState(this.handler == null, "Driver handler already set"); + this.handler = handler; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/Behaviour.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/Behaviour.java new file mode 100644 index 00000000..6e28aa86 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/Behaviour.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.net.driver; + +/** + * Representation of a facet of device behaviour that can be used to talk about + * a device (in context of {@link DriverData}) or to a device (in context of + * {@link DriverHandler}). + */ +public interface Behaviour { + + /** + * Returns the driver data context. + * + * @return driver data + */ + DriverData data(); + + /** + * Sets the driver data context on this this behaviour should operate. + * + * @param data driver data + */ + void setData(DriverData data); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriver.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriver.java new file mode 100644 index 00000000..b7a9f2b7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriver.java @@ -0,0 +1,214 @@ +/* + * 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.driver; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; + +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.ImmutableMap.copyOf; + +/** + * Default implementation of extensible driver. + */ +public class DefaultDriver implements Driver { + + private final String name; + private final Driver parent; + + private final String manufacturer; + private final String hwVersion; + private final String swVersion; + + private final Map, Class> behaviours; + private final Map properties; + + /** + * Creates a driver with the specified name. + * + * @param name driver name + * @param parent optional parent driver + * @param manufacturer device manufacturer + * @param hwVersion device hardware version + * @param swVersion device software version + * @param behaviours device behaviour classes + * @param properties properties for configuration of device behaviour classes + */ + public DefaultDriver(String name, Driver parent, String manufacturer, + String hwVersion, String swVersion, + Map, Class> behaviours, + Map properties) { + this.name = checkNotNull(name, "Name cannot be null"); + this.parent = parent; + this.manufacturer = checkNotNull(manufacturer, "Manufacturer cannot be null"); + this.hwVersion = checkNotNull(hwVersion, "HW version cannot be null"); + this.swVersion = checkNotNull(swVersion, "SW version cannot be null"); + this.behaviours = copyOf(checkNotNull(behaviours, "Behaviours cannot be null")); + this.properties = copyOf(checkNotNull(properties, "Properties cannot be null")); + } + + @Override + public Driver merge(Driver other) { + checkArgument(parent == null || Objects.equals(parent, other.parent()), + "Parent drivers are not the same"); + + // Merge the behaviours. + Map, Class> + behaviours = Maps.newHashMap(); + behaviours.putAll(this.behaviours); + other.behaviours().forEach(b -> behaviours.put(b, other.implementation(b))); + + // Merge the properties. + ImmutableMap.Builder properties = ImmutableMap.builder(); + properties.putAll(this.properties).putAll(other.properties()); + + return new DefaultDriver(name, other.parent(), manufacturer, hwVersion, swVersion, + ImmutableMap.copyOf(behaviours), properties.build()); + } + + @Override + public String name() { + return name; + } + + @Override + public String manufacturer() { + return manufacturer; + } + + @Override + public String hwVersion() { + return hwVersion; + } + + @Override + public String swVersion() { + return swVersion; + } + + @Override + public Driver parent() { + return parent; + } + + @Override + public Set> behaviours() { + return behaviours.keySet(); + } + + @Override + public Class implementation(Class behaviour) { + return behaviours.get(behaviour); + } + + @Override + public boolean hasBehaviour(Class behaviourClass) { + return behaviours.containsKey(behaviourClass) || + (parent != null && parent.hasBehaviour(behaviourClass)); + } + + @Override + public T createBehaviour(DriverData data, + Class behaviourClass) { + T behaviour = createBehaviour(data, null, behaviourClass); + if (behaviour != null) { + return behaviour; + } else if (parent != null) { + return parent.createBehaviour(data, behaviourClass); + } + throw new IllegalArgumentException(behaviourClass.getName() + " not supported"); + } + + @Override + public T createBehaviour(DriverHandler handler, + Class behaviourClass) { + T behaviour = createBehaviour(handler.data(), handler, behaviourClass); + if (behaviour != null) { + return behaviour; + } else if (parent != null) { + return parent.createBehaviour(handler, behaviourClass); + } + throw new IllegalArgumentException(behaviourClass.getName() + " not supported"); + } + + // Creates an instance of behaviour primed with the specified driver data. + private T createBehaviour(DriverData data, DriverHandler handler, + Class behaviourClass) { + //checkArgument(handler != null || !HandlerBehaviour.class.isAssignableFrom(behaviourClass), + // "{} is applicable only to handler context", behaviourClass.getName()); + + // Locate the implementation of the requested behaviour. + Class implementation = behaviours.get(behaviourClass); + if (implementation != null) { + // Create an instance of the behaviour and apply data as its context. + T behaviour = createBehaviour(behaviourClass, implementation); + behaviour.setData(data); + + // If this is a handler behaviour, also apply handler as its context. + if (handler != null) { + ((HandlerBehaviour) behaviour).setHandler(handler); + } + return behaviour; + } + return null; + } + + @SuppressWarnings("unchecked") + private T createBehaviour(Class behaviourClass, + Class implementation) { + try { + return (T) implementation.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + // TODO: add a specific unchecked exception + throw new IllegalArgumentException("Unable to create behaviour", e); + } + } + + @Override + public Set keys() { + return properties.keySet(); + } + + @Override + public String value(String key) { + return properties.get(key); + } + + @Override + public Map properties() { + return properties; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("name", name) + .add("parent", parent) + .add("manufacturer", manufacturer) + .add("hwVersion", hwVersion) + .add("swVersion", swVersion) + .add("behaviours", behaviours) + .add("properties", properties) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverData.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverData.java new file mode 100644 index 00000000..76d7932d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverData.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.driver; + +import com.google.common.collect.ImmutableSet; +import org.onosproject.net.DeviceId; +import org.onosproject.net.MutableAnnotations; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Default implementation of driver data descriptor. + */ +public class DefaultDriverData implements DriverData { + + private final Driver driver; + private final DeviceId deviceId; + private final Map properties; + + /** + * Creates new driver data. + * + * @param driver parent driver type + * @param deviceId device identifier + */ + public DefaultDriverData(Driver driver, DeviceId deviceId) { + this.driver = driver; + this.deviceId = deviceId; + this.properties = new HashMap<>(); + } + + @Override + public Driver driver() { + return driver; + } + + @Override + public DeviceId deviceId() { + return deviceId; + } + + @Override + public T behaviour(Class behaviourClass) { + return driver.createBehaviour(this, behaviourClass); + } + + @Override + public MutableAnnotations set(String key, String value) { + properties.put(key, value); + return this; + } + + @Override + public MutableAnnotations clear(String... keys) { + if (keys.length == 0) { + properties.clear(); + } else { + for (String key : keys) { + properties.remove(key); + } + } + return this; + } + + @Override + public Set keys() { + return ImmutableSet.copyOf(properties.keySet()); + } + + @Override + public String value(String key) { + return properties.get(key); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("type", driver) + .add("properties", properties) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverHandler.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverHandler.java new file mode 100644 index 00000000..28fdb2f3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverHandler.java @@ -0,0 +1,67 @@ +/* + * 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.driver; + +import org.onlab.osgi.DefaultServiceDirectory; +import org.onlab.osgi.ServiceDirectory; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Default implementation of driver handler. + */ +public class DefaultDriverHandler implements DriverHandler { + + private final DefaultDriverData data; + + // Reference to service directory to provide run-time context. + protected static ServiceDirectory serviceDirectory = new DefaultServiceDirectory(); + + /** + * Creates new driver handler with the attached driver data. + * + * @param data driver data to attach + */ + public DefaultDriverHandler(DefaultDriverData data) { + this.data = data; + } + + @Override + public Driver driver() { + return data.driver(); + } + + @Override + public DriverData data() { + return data; + } + + @Override + public T behaviour(Class behaviourClass) { + return data.driver().createBehaviour(this, behaviourClass); + } + + @Override + public T get(Class serviceClass) { + return serviceDirectory.get(serviceClass); + } + + @Override + public String toString() { + return toStringHelper(this).add("data", data).toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverProvider.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverProvider.java new file mode 100644 index 00000000..b2b5281c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverProvider.java @@ -0,0 +1,86 @@ +/* + * 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.driver; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; + +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Default driver provider implementation. + */ +public class DefaultDriverProvider implements DriverProvider { + + protected final Map drivers = Maps.newConcurrentMap(); + + @Override + public Set getDrivers() { + return ImmutableSet.copyOf(drivers.values()); + } + + /** + * Adds the specified drivers to the provider. + * + * @param drivers drivers to be added + */ + public void addDrivers(Set drivers) { + drivers.forEach(this::addDriver); + } + + /** + * Adds the specified driver to the provider. + * + * @param driver driver to be provided + */ + public void addDriver(Driver driver) { + Driver ddc = drivers.get(driver.name()); + if (ddc == null) { + // If we don't have the driver yet, just use the new one. + drivers.put(driver.name(), driver); + } else { + // Otherwise merge the existing driver with the new one and rebind. + drivers.put(driver.name(), ddc.merge(driver)); + } + } + + /** + * Removes the specified drivers from the provider. + * + * @param drivers drivers to be removed + */ + public void removeDrivers(Set drivers) { + drivers.forEach(this::removeDriver); + } + + /** + * Removes the specified driver from the provider. + * + * @param driver driver to be removed + */ + public void removeDriver(Driver driver) { + // TODO: make selective if possible + drivers.remove(driver.name()); + } + + @Override + public String toString() { + return toStringHelper(this).add("drivers", drivers).toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverProviderService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverProviderService.java new file mode 100644 index 00000000..153c7c56 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DefaultDriverProviderService.java @@ -0,0 +1,23 @@ +/* + * 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.driver; + +/** + * Service representing availability of default drivers. + */ +public interface DefaultDriverProviderService { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/Driver.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/Driver.java new file mode 100644 index 00000000..50611b14 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/Driver.java @@ -0,0 +1,132 @@ +/* + * 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.driver; + +import org.onosproject.net.Annotations; + +import java.util.Map; +import java.util.Set; + +/** + * Representation of a specific family of device drivers. Behaviour configuration + * data is stored using {@link org.onosproject.net.Annotations}. + */ +public interface Driver extends Annotations { + + /** + * Returns the driver name. This is expected to be a reverse-DNS, + * Java package-like name. + * + * @return driver name + */ + String name(); + + /** + * Returns the parent driver from which this driver inherits behaviours + * and properties. + * + * @return parent driver; null if driver has no parent + */ + Driver parent(); + + /** + * Returns the device manufacturer name. + * + * @return manufacturer name + */ + String manufacturer(); + + /** + * Returns the device hardware version. + * + * @return hardware version + */ + String hwVersion(); + + /** + * Returns the device software version. + * + * @return software version + */ + String swVersion(); + + /** + * Returns the set of behaviours supported by this driver. + * It reflects behaviours of only this driver and not its parent. + * + * @return set of device driver behaviours + */ + Set> behaviours(); + + /** + * Returns the implementation class for the specified behaviour. + * It reflects behaviours of only this driver and not its parent. + * + * @param behaviour behaviour interface + * @return implementation class + */ + Class implementation(Class behaviour); + + /** + * Indicates whether or not the driver, or any of its parents, support + * the specified class of behaviour. It + * + * @param behaviourClass behaviour class + * @return true if behaviour is supported + */ + boolean hasBehaviour(Class behaviourClass); + + /** + * Creates an instance of behaviour primed with the specified driver data. + * If the current driver does not support the specified behaviour and the + * driver has parent, the request is delegated to the parent driver. + * + * @param data driver data context + * @param behaviourClass driver behaviour class + * @param type of behaviour + * @return behaviour instance + */ + T createBehaviour(DriverData data, Class behaviourClass); + + /** + * Creates an instance of behaviour primed with the specified driver data. + * If the current driver does not support the specified behaviour and the + * driver has parent, the request is delegated to the parent driver. + * + * @param handler driver handler context + * @param behaviourClass driver behaviour class + * @param type of behaviour + * @return behaviour instance + */ + T createBehaviour(DriverHandler handler, Class behaviourClass); + + /** + * Returns the set of annotations as map of key/value properties. + * + * @return map of properties + */ + Map properties(); + + /** + * Merges the specified driver behaviours and properties into this one, + * giving preference to the other driver when dealing with conflicts. + * + * @param other other driver + * @return merged driver + */ + Driver merge(Driver other); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverAdminService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverAdminService.java new file mode 100644 index 00000000..e7fa1385 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverAdminService.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.net.driver; + +import java.util.Set; + +/** + * Service for managing drivers and driver behaviour implementations. + */ +public interface DriverAdminService extends DriverService { + + /** + * Returns the set of driver providers currently registered. + * + * @return registered driver providers + */ + Set getProviders(); + + /** + * Registers the specified driver provider. + * + * @param provider driver provider to register + */ + void registerProvider(DriverProvider provider); + + /** + * Unregisters the specified driver provider. + * + * @param provider driver provider to unregister + */ + void unregisterProvider(DriverProvider provider); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverConnect.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverConnect.java new file mode 100644 index 00000000..1d510913 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverConnect.java @@ -0,0 +1,36 @@ +/* + * 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.driver; + +/** + * Abstraction of handler behaviour used to set-up and tear-down driver + * connection with a device. + */ +public interface DriverConnect extends HandlerBehaviour { + + /** + * Connects to the device. + * + * @param credentials optional login credentials in string form + */ + void connect(String... credentials); + + /** + * Disconnects from the device. + */ + void disconnect(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverData.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverData.java new file mode 100644 index 00000000..1d66ea9a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverData.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.net.driver; + +import org.onosproject.net.DeviceId; +import org.onosproject.net.MutableAnnotations; + +/** + * Container for data about a device. Data is stored using + * {@link org.onosproject.net.MutableAnnotations}. + */ +public interface DriverData extends MutableAnnotations { + + /** + * Returns the parent device driver. + * + * @return device driver + */ + Driver driver(); + + /** + * Returns the device identifier. + * + * @return device identifier + */ + DeviceId deviceId(); + + /** + * Returns the specified facet of behaviour to access the device data. + * + * @param behaviourClass behaviour class + * @param type of behaviour + * @return requested behaviour or null if not supported + */ + T behaviour(Class behaviourClass); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverHandler.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverHandler.java new file mode 100644 index 00000000..202708ba --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverHandler.java @@ -0,0 +1,57 @@ +/* + * 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.driver; + +/** + * Representation of context for interacting with a device. + */ +public interface DriverHandler { + + /** + * Returns the parent device driver. + * + * @return device driver + */ + Driver driver(); + + /** + * Returns the device driver data. + * + * @return device driver data + */ + DriverData data(); + + /** + * Returns the specified facet of behaviour to interact with the device. + * + * @param behaviourClass behaviour class + * @param type of behaviour + * @return behaviour + */ + T behaviour(Class behaviourClass); + + /** + * Returns the reference to the implementation of the specified service. + * Provides access to run-time context. + * + * @param serviceClass service class + * @param type of service + * @return service implementation + * @throws org.onlab.osgi.ServiceNotFoundException if service is unavailable + */ + T get(Class serviceClass); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverProvider.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverProvider.java new file mode 100644 index 00000000..354d93e9 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverProvider.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.net.driver; + +import java.util.Set; + +/** + * Represents entity capable of providing device drivers and their + * behaviours. + */ +public interface DriverProvider { + + /** + * Returns the set of driver types and behaviour implementations to be + * made available by this provider. + * + * @return set of driver types and their behaviours + */ + Set getDrivers(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverResolver.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverResolver.java new file mode 100644 index 00000000..094c710f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverResolver.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.net.driver; + +/** + * Entity capable of resolving a driver using its name. + */ +public interface DriverResolver { + + /** + * Returns the specified driver. + * + * @param driverName driver name + * @return driver + * @throws org.onlab.util.ItemNotFoundException if driver with the given + * name is not found + */ + Driver getDriver(String driverName); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverService.java new file mode 100644 index 00000000..1a74255b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/DriverService.java @@ -0,0 +1,83 @@ +/* + * 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.driver; + +import org.onosproject.net.DeviceId; + +import java.util.Set; + +/** + * Service for obtaining drivers and driver behaviour implementations. + */ +public interface DriverService extends DriverResolver { + + /** + * Returns the overall set of drivers being provided. + * + * @return provided drivers + */ + Set getDrivers(); + + /** + * Returns the set of drivers which support the specified behaviour. + * + * @param withBehaviour behaviour class to query by + * @return provided drivers + */ + Set getDrivers(Class withBehaviour); + + /** + * Returns the driver that matches the specified primordial device + * discovery information. + * + * @param mfr device manufacturer + * @param hw device hardware name/version + * @param sw device software version + * @return driver or null of no matching one is found + */ + Driver getDriver(String mfr, String hw, String sw); + + /** + * Returns the driver for the specified device. If the device carries + * {@code driver} annotation, its value is used to look-up the driver. + * Otherwise, the device manufacturer, hardware and software version + * attributes are used to look-up the driver. First using their literal + * values and if no driver is found, using ERE matching against the + * driver manufacturer, hardware and software version fields. + * + * @param deviceId device identifier + * @return driver or null of no matching one is found + * @throws org.onlab.util.ItemNotFoundException if device or driver for it + * are not found + */ + Driver getDriver(DeviceId deviceId); + + /** + * Creates a new driver handler for interacting with the specified device. + * The driver is looked-up using the same semantics as + * {@link #getDriver(DeviceId)} method. + * + * @param deviceId device identifier + * @param credentials optional login credentials in string form + * @return driver handler + * @throws org.onlab.util.ItemNotFoundException if device or driver for it + * are not found + */ + DriverHandler createHandler(DeviceId deviceId, String... credentials); + + // TODO: Devise a mechanism for retaining DriverData for devices + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/HandlerBehaviour.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/HandlerBehaviour.java new file mode 100644 index 00000000..b5771ac1 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/HandlerBehaviour.java @@ -0,0 +1,38 @@ +/* + * 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.driver; + +/** + * Representation of a facet of device behaviour that can be used to interact + * with a device (in context of {@link org.onosproject.net.driver.DriverHandler}). + */ +public interface HandlerBehaviour extends Behaviour { + + /** + * Returns the driver handler context on which this behaviour operates. + * + * @return driver handler context + */ + DriverHandler handler(); + + /** + * Sets the driver handler context for this behaviour. + * + * @param handler driver handler + */ + void setHandler(DriverHandler handler); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/XmlDriverLoader.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/XmlDriverLoader.java new file mode 100644 index 00000000..fc5e04a1 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/XmlDriverLoader.java @@ -0,0 +1,176 @@ +/* + * 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.driver; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.HierarchicalConfiguration; +import org.apache.commons.configuration.XMLConfiguration; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +/** + * Utility capable of reading driver configuration XML resources and producing + * a device driver provider as a result. + *

+ * The drivers stream structure is as follows: + *

+ *
+ *     <drivers>
+ *         <driver name=“...” [manufacturer="..." hwVersion="..." swVersion="..."]>
+ *             <behaviour api="..." impl="..."/>
+ *             ...
+ *             [<property name=“key”>value</key>]
+ *             ...
+ *         </driver>
+ *         ...
+ *     </drivers>
+ * 
+ */ +public class XmlDriverLoader { + + private static final String DRIVERS = "drivers"; + private static final String DRIVER = "driver"; + + private static final String BEHAVIOUR = "behaviour"; + private static final String PROPERTY = "property"; + + private static final String NAME = "[@name]"; + private static final String EXTENDS = "[@extends]"; + private static final String MFG = "[@manufacturer]"; + private static final String HW = "[@hwVersion]"; + private static final String SW = "[@swVersion]"; + private static final String API = "[@api]"; + private static final String IMPL = "[@impl]"; + + private final ClassLoader classLoader; + + private Map drivers = Maps.newHashMap(); + + /** + * Creates a new driver loader capable of loading drivers from the supplied + * class loader. + * + * @param classLoader class loader to use + */ + public XmlDriverLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + /** + * Loads the specified drivers resource as an XML stream and parses it to + * produce a ready-to-register driver provider. + * + * @param driversStream stream containing the drivers definitions + * @param resolver driver resolver + * @return driver provider + * @throws java.io.IOException if issues are encountered reading the stream + * or parsing the driver definitions within + */ + public DefaultDriverProvider loadDrivers(InputStream driversStream, + DriverResolver resolver) throws IOException { + try { + XMLConfiguration cfg = new XMLConfiguration(); + cfg.setRootElementName(DRIVERS); + cfg.setAttributeSplittingDisabled(true); + + cfg.load(driversStream); + return loadDrivers(cfg, resolver); + } catch (ConfigurationException e) { + throw new IOException("Unable to load drivers", e); + } + } + + /** + * Loads a driver provider from the supplied hierarchical configuration. + * + * @param driversCfg hierarchical configuration containing the drivers definitions + * @param resolver driver resolver + * @return driver provider + */ + public DefaultDriverProvider loadDrivers(HierarchicalConfiguration driversCfg, + DriverResolver resolver) { + DefaultDriverProvider provider = new DefaultDriverProvider(); + for (HierarchicalConfiguration cfg : driversCfg.configurationsAt(DRIVER)) { + DefaultDriver driver = loadDriver(cfg, resolver); + drivers.put(driver.name(), driver); + provider.addDriver(driver); + } + drivers.clear(); + return provider; + } + + /** + * Loads a driver from the supplied hierarchical configuration. + * + * @param driverCfg hierarchical configuration containing the driver definition + * @param resolver driver resolver + * @return driver + */ + public DefaultDriver loadDriver(HierarchicalConfiguration driverCfg, + DriverResolver resolver) { + String name = driverCfg.getString(NAME); + String parentName = driverCfg.getString(EXTENDS); + String manufacturer = driverCfg.getString(MFG, ""); + String hwVersion = driverCfg.getString(HW, ""); + String swVersion = driverCfg.getString(SW, ""); + + Driver parent = parentName != null ? resolve(parentName, resolver) : null; + return new DefaultDriver(name, parent, manufacturer, hwVersion, swVersion, + parseBehaviours(driverCfg), + parseProperties(driverCfg)); + } + + // Resolves the driver by name locally at first and then using the specified resolver. + private Driver resolve(String parentName, DriverResolver resolver) { + Driver driver = drivers.get(parentName); + return driver != null ? driver : + (resolver != null ? resolver.getDriver(parentName) : null); + } + + // Parses the behaviours section. + private Map, Class> + parseBehaviours(HierarchicalConfiguration driverCfg) { + ImmutableMap.Builder, + Class> behaviours = ImmutableMap.builder(); + for (HierarchicalConfiguration b : driverCfg.configurationsAt(BEHAVIOUR)) { + behaviours.put(getClass(b.getString(API)), getClass(b.getString(IMPL))); + } + return behaviours.build(); + } + + // Parses the properties section. + private Map parseProperties(HierarchicalConfiguration driverCfg) { + ImmutableMap.Builder properties = ImmutableMap.builder(); + for (HierarchicalConfiguration b : driverCfg.configurationsAt(PROPERTY)) { + properties.put(b.getString(NAME), (String) b.getRootNode().getValue()); + } + return properties.build(); + } + + @SuppressWarnings("unchecked") + private Class getClass(String className) { + try { + return (Class) classLoader.loadClass(className); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("Unable to load class " + className, e); + } + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/package-info.java new file mode 100644 index 00000000..fbc39a89 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/driver/package-info.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +/** + * Set of facilities to allow the platform to be extended with + * device specific behaviours and to allow modeling device behaviours while + * hiding details of specific device driver implementations. + *

+ * {@link org.onosproject.net.driver.Driver} is a representation of a + * specific family of devices supports set of + * {@link org.onosproject.net.driver.Behaviour behaviour classes}. Default + * implementation is provided by the platform and allows DriverProviders to + * add different behaviour implementations via DriverService. + *

+ *

+ * {@link org.onosproject.net.driver.DriverData} is a container for data + * learned about a device. It is associated with a specific + * {@link org.onosproject.net.driver.Driver} + * and provides set of {@link org.onosproject.net.driver.Behaviour behaviours} + * for talking about a device. A default + * implementation provided by platform and has mutable key/value store for use by + * implementations of {@link org.onosproject.net.driver.Behaviour behaviours}. + *

+ *

+ * {@link org.onosproject.net.driver.DriverHandler} is an entity used as a + * context to interact with a device. It has a peer + * {@link org.onosproject.net.driver.DriverData} instance, which is used to + * store information learned about a device. It also + * provides set of {@link org.onosproject.net.driver.Behaviour behaviours} + * for talking to a device. + *

+ *

+ * {@link org.onosproject.net.driver.DriverService} can be used to query the + * inventory of device drivers and their behaviours, while the + * {@link org.onosproject.net.driver.DriverAdminService} allows adding/removing + * drivers and managing behaviour implementations. + * {@link org.onosproject.net.driver.DriverProvider} is an entity capable + * of add/removing drivers and supplying and managing behaviour + * implementations. A default implementation is provided by the framework along + * with a {@link org.onosproject.net.driver.XmlDriverLoader loader utility} to + * create a driver provider from an XML file structured as follows: + *

+ *     <drivers>
+ *         <driver name=“...” [manufacturer="..." hwVersion="..." swVersion="..."]>
+ *             <behaviour api="..." impl="..."/>
+ *             ...
+ *             [<property name=“key”>value</key>]
+ *             ...
+ *         </driver>
+ *         ...
+ *     </drivers>
+ * 
+ * + */ +package org.onosproject.net.driver; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/EdgePortEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/EdgePortEvent.java new file mode 100644 index 00000000..85e6a1b5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/EdgePortEvent.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.edge; + +import org.onosproject.event.AbstractEvent; +import org.onosproject.net.ConnectPoint; + +/** + * Describes an event pertaining to edge-port inventory. + */ +public class EdgePortEvent extends AbstractEvent { + + public enum Type { + /** + * Signifies that a new edge port was detected. + */ + EDGE_PORT_ADDED, + + /** + * Signifies that a new edge port vanished. + */ + EDGE_PORT_REMOVED + } + + /** + * Creates a new edge port event. + * + * @param type event type + * @param subject connection point subject + */ + public EdgePortEvent(Type type, ConnectPoint subject) { + super(type, subject); + } + + /** + * Creates a new edge port event. + * + * @param type event type + * @param subject connection point subject + * @param time occurrence time + */ + public EdgePortEvent(Type type, ConnectPoint subject, long time) { + super(type, subject, time); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/EdgePortListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/EdgePortListener.java new file mode 100644 index 00000000..dae03beb --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/EdgePortListener.java @@ -0,0 +1,24 @@ +/* + * 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.edge; + +import org.onosproject.event.EventListener; + +/** + * Entity capable of receiving edge port events. + */ +public interface EdgePortListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/EdgePortService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/EdgePortService.java new file mode 100644 index 00000000..89a2c171 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/EdgePortService.java @@ -0,0 +1,75 @@ +/* + * 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.edge; + +import org.onosproject.event.ListenerService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.flow.TrafficTreatment; + +import java.nio.ByteBuffer; +import java.util.Optional; + +/** + * Service for interacting with an inventory of network edge ports. A port + * is considered an edge port if it is an active port and does not have an + * infrastructure link associated with it. + */ +public interface EdgePortService + extends ListenerService { + + /** + * Indicates whether or not the specified connection point is an edge point. + * + * @param point connection point + * @return true if edge point + */ + boolean isEdgePoint(ConnectPoint point); + + /** + * Returns a collection of all edge point within the current topology. + * + * @return iterable collection of all edge points + */ + Iterable getEdgePoints(); + + /** + * Returns a collection of all edge point for the specified device. + * + * @param deviceId device identifier + * @return iterable collection of all edge points for the device + */ + Iterable getEdgePoints(DeviceId deviceId); + + /** + * Emits the specified packet, with optional treatment to all edge ports. + * + * @param data packet data + * @param treatment optional traffic treatment to apply to the packet + */ + void emitPacket(ByteBuffer data, Optional treatment); + + /** + * Emits the specified packet, with optional treatment to all edge ports. + * + * @param deviceId device where to send the packet out + * @param data packet data + * @param treatment optional traffic treatment to apply to the packet + */ + void emitPacket(DeviceId deviceId, ByteBuffer data, + Optional treatment); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/package-info.java new file mode 100644 index 00000000..d637f195 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/edge/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. + */ + +/** + * Service for interacting with network edge. + */ +package org.onosproject.net.edge; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/BatchOperation.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/BatchOperation.java new file mode 100644 index 00000000..09e34d88 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/BatchOperation.java @@ -0,0 +1,128 @@ +/* + * Copyright 2014 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 java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A list of BatchOperationEntry. + * + * @param the enum of operators
+ * This enum must be defined in each sub-classes. + */ +public abstract class BatchOperation> { + + private final List ops; + + /** + * Creates new {@link BatchOperation} object. + */ + public BatchOperation() { + ops = new LinkedList<>(); + } + + /** + * Creates {@link BatchOperation} object from a list of batch operation + * entries. + * + * @param batchOperations the list of batch operation entries. + */ + public BatchOperation(Collection batchOperations) { + ops = new LinkedList<>(checkNotNull(batchOperations)); + } + + /** + * Removes all operations maintained in this object. + */ + public void clear() { + ops.clear(); + } + + /** + * Returns the number of operations in this object. + * + * @return the number of operations in this object + */ + public int size() { + return ops.size(); + } + + /** + * Returns the operations in this object. + * + * @return the operations in this object + */ + public List getOperations() { + return Collections.unmodifiableList(ops); + } + + /** + * Adds an operation. + * FIXME: Brian promises that the Intent Framework + * will not modify the batch operation after it has submitted it. + * Ali would prefer immutablity, but trusts brian for better or + * for worse. + * + * @param entry the operation to be added + * @return this object if succeeded, null otherwise + */ + public BatchOperation addOperation(T entry) { + return ops.add(entry) ? this : null; + } + + /** + * Add all operations from another batch to this batch. + * + * @param another another batch + * @return true if success + */ + public boolean addAll(BatchOperation another) { + return ops.addAll(another.getOperations()); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null) { + return false; + } + + if (getClass() != o.getClass()) { + return false; + } + BatchOperation other = (BatchOperation) o; + + return this.ops.equals(other.ops); + } + + @Override + public int hashCode() { + return ops.hashCode(); + } + + @Override + public String toString() { + return ops.toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/BatchOperationEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/BatchOperationEntry.java new file mode 100644 index 00000000..cc054286 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/BatchOperationEntry.java @@ -0,0 +1,90 @@ +/* + * Copyright 2014-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 java.util.Objects; + +import com.google.common.base.MoreObjects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A super class for batch operation entry classes. + *

+ * This is the interface to classes which are maintained by BatchOperation as + * its entries. + */ +public class BatchOperationEntry, U> { + + private final T operator; + private final U target; + + /** + * Constructs new instance for the entry of the BatchOperation. + * + * @param operator the operator of this operation + * @param target the target object of this operation + */ + public BatchOperationEntry(T operator, U target) { + this.operator = checkNotNull(operator); + this.target = checkNotNull(target); + } + + /** + * Gets the target object of this operation. + * + * @return the target object of this operation + */ + public U target() { + return target; + } + + /** + * Gets the operator of this operation. + * + * @return the operator of this operation + */ + public T operator() { + return operator; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + BatchOperationEntry other = (BatchOperationEntry) o; + return (this.operator == other.operator) && + Objects.equals(this.target, other.target); + } + + @Override + public int hashCode() { + return Objects.hash(operator, target); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("operator", operator) + .add("target", target) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/BatchOperationResult.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/BatchOperationResult.java new file mode 100644 index 00000000..684a8698 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/BatchOperationResult.java @@ -0,0 +1,38 @@ +/* + * Copyright 2014 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 java.util.Set; + +/** + * Interface capturing the result of a batch operation. + * + */ +public interface BatchOperationResult { + + /** + * Returns whether the operation was successful. + * @return true if successful, false otherwise + */ + boolean isSuccess(); + + /** + * Obtains a set of items which failed. + * @return a set of failures + */ + Set failedItems(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/CompletedBatchOperation.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/CompletedBatchOperation.java new file mode 100644 index 00000000..3afae5ef --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/CompletedBatchOperation.java @@ -0,0 +1,96 @@ +/* + * Copyright 2014-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 com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableSet; +import org.onosproject.net.DeviceId; + +import java.util.Collections; +import java.util.Set; + +/** + * Representation of a completed flow rule batch operation. + */ +public class CompletedBatchOperation implements BatchOperationResult { + + private final boolean success; + private final Set failures; + private final Set failedIds; + private final DeviceId deviceId; + + /** + * Creates a new batch completion result. + * + * @param success indicates whether the completion is successful + * @param failures set of any failures encountered + * @param failedIds (optional) set of failed operation ids + * @param deviceId the device this operation completed for + */ + public CompletedBatchOperation(boolean success, Set failures, + Set failedIds, DeviceId deviceId) { + this.success = success; + this.failures = ImmutableSet.copyOf(failures); + this.failedIds = ImmutableSet.copyOf(failedIds); + this.deviceId = deviceId; + } + + /** + * Creates a new batch completion result. + * + * @param success indicates whether the completion is successful. + * @param failures set of any failures encountered + * @param deviceId the device this operation completed for + */ + public CompletedBatchOperation(boolean success, Set failures, + DeviceId deviceId) { + this.success = success; + this.failures = ImmutableSet.copyOf(failures); + this.failedIds = Collections.emptySet(); + this.deviceId = deviceId; + } + + + + @Override + public boolean isSuccess() { + return success; + } + + @Override + public Set failedItems() { + return failures; + } + + public Set failedIds() { + return failedIds; + } + + public DeviceId deviceId() { + return this.deviceId; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("success?", success) + .add("failedItems", failures) + .add("failedIds", failedIds) + .add("deviceId", deviceId) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultFlowEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultFlowEntry.java new file mode 100644 index 00000000..f7e7708e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultFlowEntry.java @@ -0,0 +1,137 @@ +/* + * Copyright 2014-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; +import static org.slf4j.LoggerFactory.getLogger; + +import org.slf4j.Logger; + +public class DefaultFlowEntry extends DefaultFlowRule + implements StoredFlowEntry { + + private static final Logger log = getLogger(DefaultFlowEntry.class); + + private long life; + private long packets; + private long bytes; + private FlowEntryState state; + + private long lastSeen = -1; + + private final int errType; + + private final int errCode; + + public DefaultFlowEntry(FlowRule rule, FlowEntryState state, + long life, long packets, long bytes) { + super(rule); + this.state = state; + this.life = life; + this.packets = packets; + this.bytes = bytes; + this.errCode = -1; + this.errType = -1; + this.lastSeen = System.currentTimeMillis(); + } + + public DefaultFlowEntry(FlowRule rule) { + super(rule); + this.state = FlowEntryState.PENDING_ADD; + this.life = 0; + this.packets = 0; + this.bytes = 0; + this.errCode = -1; + this.errType = -1; + this.lastSeen = System.currentTimeMillis(); + } + + public DefaultFlowEntry(FlowRule rule, int errType, int errCode) { + super(rule); + this.state = FlowEntryState.FAILED; + this.errType = errType; + this.errCode = errCode; + this.lastSeen = System.currentTimeMillis(); + } + + @Override + public long life() { + return life; + } + + @Override + public long packets() { + return packets; + } + + @Override + public long bytes() { + return bytes; + } + + @Override + public FlowEntryState state() { + return this.state; + } + + @Override + public long lastSeen() { + return lastSeen; + } + + @Override + public void setLastSeen() { + this.lastSeen = System.currentTimeMillis(); + } + + @Override + public void setState(FlowEntryState newState) { + this.state = newState; + } + + @Override + public void setLife(long life) { + this.life = life; + } + + @Override + public void setPackets(long packets) { + this.packets = packets; + } + + @Override + public void setBytes(long bytes) { + this.bytes = bytes; + } + + @Override + public int errType() { + return this.errType; + } + + @Override + public int errCode() { + return this.errCode; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("rule", super.toString()) + .add("state", state) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultFlowRule.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultFlowRule.java new file mode 100644 index 00000000..44a4d364 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultFlowRule.java @@ -0,0 +1,390 @@ +/* + * Copyright 2014 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.core.ApplicationId; +import org.onosproject.core.DefaultGroupId; +import org.onosproject.core.GroupId; +import org.onosproject.net.DeviceId; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +public class DefaultFlowRule implements FlowRule { + + private final DeviceId deviceId; + private final int priority; + private final TrafficSelector selector; + private final TrafficTreatment treatment; + private final long created; + + private final FlowId id; + + private final Short appId; + + private final int timeout; + private final boolean permanent; + private final GroupId groupId; + + private final Integer tableId; + private final FlowRuleExtPayLoad payLoad; + + public DefaultFlowRule(FlowRule rule) { + this.deviceId = rule.deviceId(); + this.priority = rule.priority(); + this.selector = rule.selector(); + this.treatment = rule.treatment(); + this.appId = rule.appId(); + this.groupId = rule.groupId(); + this.id = rule.id(); + this.timeout = rule.timeout(); + this.permanent = rule.isPermanent(); + this.created = System.currentTimeMillis(); + this.tableId = rule.tableId(); + this.payLoad = rule.payLoad(); + } + + private DefaultFlowRule(DeviceId deviceId, TrafficSelector selector, + TrafficTreatment treatment, Integer priority, + FlowId flowId, Boolean permanent, Integer timeout, + Integer tableId) { + + this.deviceId = deviceId; + this.selector = selector; + this.treatment = treatment; + this.priority = priority; + this.appId = (short) (flowId.value() >>> 48); + this.id = flowId; + this.permanent = permanent; + this.timeout = timeout; + this.tableId = tableId; + this.created = System.currentTimeMillis(); + + + //FIXME: fields below will be removed. + this.groupId = new DefaultGroupId(0); + this.payLoad = null; + } + + /** + * Support for the third party flow rule. Creates a flow rule of flow table. + * + * @param deviceId the identity of the device where this rule applies + * @param selector the traffic selector that identifies what traffic this + * rule + * @param treatment the traffic treatment that applies to selected traffic + * @param priority the flow rule priority given in natural order + * @param appId the application id of this flow + * @param timeout the timeout for this flow requested by an application + * @param permanent whether the flow is permanent i.e. does not time out + * @param payLoad 3rd-party origin private flow + */ + public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector, + TrafficTreatment treatment, int priority, + ApplicationId appId, int timeout, boolean permanent, + FlowRuleExtPayLoad payLoad) { + + if (priority < FlowRule.MIN_PRIORITY) { + throw new IllegalArgumentException("Priority cannot be less than " + + MIN_PRIORITY); + } + + this.deviceId = deviceId; + this.priority = priority; + this.selector = selector; + this.treatment = treatment; + this.appId = appId.id(); + this.groupId = new DefaultGroupId(0); + this.timeout = timeout; + this.permanent = permanent; + this.tableId = 0; + this.created = System.currentTimeMillis(); + this.payLoad = payLoad; + + /* + * id consists of the following. | appId (16 bits) | groupId (16 bits) | + * flowId (32 bits) | + */ + this.id = FlowId.valueOf((((long) this.appId) << 48) + | (((long) this.groupId.id()) << 32) + | (this.hash() & 0xffffffffL)); + } + + /** + * Support for the third party flow rule. Creates a flow rule of group + * table. + * + * @param deviceId the identity of the device where this rule applies + * @param selector the traffic selector that identifies what traffic this + * rule + * @param treatment the traffic treatment that applies to selected traffic + * @param priority the flow rule priority given in natural order + * @param appId the application id of this flow + * @param groupId the group id of this flow + * @param timeout the timeout for this flow requested by an application + * @param permanent whether the flow is permanent i.e. does not time out + * @param payLoad 3rd-party origin private flow + * + */ + public DefaultFlowRule(DeviceId deviceId, TrafficSelector selector, + TrafficTreatment treatment, int priority, + ApplicationId appId, GroupId groupId, int timeout, + boolean permanent, FlowRuleExtPayLoad payLoad) { + + if (priority < FlowRule.MIN_PRIORITY) { + throw new IllegalArgumentException("Priority cannot be less than " + + MIN_PRIORITY); + } + + this.deviceId = deviceId; + this.priority = priority; + this.selector = selector; + this.treatment = treatment; + this.appId = appId.id(); + this.groupId = groupId; + this.timeout = timeout; + this.permanent = permanent; + this.created = System.currentTimeMillis(); + this.tableId = 0; + this.payLoad = payLoad; + + /* + * id consists of the following. | appId (16 bits) | groupId (16 bits) | + * flowId (32 bits) | + */ + this.id = FlowId.valueOf((((long) this.appId) << 48) + | (((long) this.groupId.id()) << 32) + | (this.hash() & 0xffffffffL)); + } + + @Override + public FlowId id() { + return id; + } + + @Override + public short appId() { + return appId; + } + + @Override + public GroupId groupId() { + return groupId; + } + + @Override + public int priority() { + return priority; + } + + @Override + public DeviceId deviceId() { + return deviceId; + } + + @Override + public TrafficSelector selector() { + return selector; + } + + @Override + public TrafficTreatment treatment() { + return treatment; + } + + @Override + /* + * The priority and statistics can change on a given treatment and selector + * + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public int hashCode() { + return Objects.hash(deviceId, selector, tableId, payLoad); + } + + //FIXME do we need this method in addition to hashCode()? + private int hash() { + return Objects.hash(deviceId, selector, tableId, payLoad); + } + + @Override + /* + * The priority and statistics can change on a given treatment and selector + * + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultFlowRule) { + DefaultFlowRule that = (DefaultFlowRule) obj; + return Objects.equals(deviceId, that.deviceId) && + Objects.equals(priority, that.priority) && + Objects.equals(selector, that.selector) && + Objects.equals(tableId, that.tableId) + && Objects.equals(payLoad, that.payLoad); + } + return false; + } + + @Override + public boolean exactMatch(FlowRule rule) { + return this.equals(rule) && + Objects.equals(this.id, rule.id()) && + Objects.equals(this.treatment, rule.treatment()); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("id", Long.toHexString(id.value())) + .add("deviceId", deviceId) + .add("priority", priority) + .add("selector", selector.criteria()) + .add("treatment", treatment == null ? "N/A" : treatment.allInstructions()) + .add("tableId", tableId) + .add("created", created) + .add("payLoad", payLoad) + .toString(); + } + + @Override + public int timeout() { + return timeout; + } + + @Override + public boolean isPermanent() { + return permanent; + } + + @Override + public int tableId() { + return tableId; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder implements FlowRule.Builder { + + private FlowId flowId; + private Integer priority; + private DeviceId deviceId; + private Integer tableId = 0; + private TrafficSelector selector; + private TrafficTreatment treatment; + private Integer timeout; + private Boolean permanent; + + @Override + public FlowRule.Builder withCookie(long cookie) { + this.flowId = FlowId.valueOf(cookie); + return this; + } + + @Override + public FlowRule.Builder fromApp(ApplicationId appId) { + this.flowId = computeFlowId(appId); + return this; + } + + @Override + public FlowRule.Builder withPriority(int priority) { + this.priority = priority; + return this; + } + + @Override + public FlowRule.Builder forDevice(DeviceId deviceId) { + this.deviceId = deviceId; + return this; + } + + @Override + public FlowRule.Builder forTable(int tableId) { + this.tableId = tableId; + return this; + } + + @Override + public FlowRule.Builder withSelector(TrafficSelector selector) { + this.selector = selector; + return this; + } + + @Override + public FlowRule.Builder withTreatment(TrafficTreatment treatment) { + this.treatment = treatment; + return this; + } + + @Override + public FlowRule.Builder makePermanent() { + this.timeout = 0; + this.permanent = true; + return this; + } + + @Override + public FlowRule.Builder makeTemporary(int timeout) { + this.permanent = false; + this.timeout = timeout; + return this; + } + + @Override + public FlowRule build() { + checkNotNull(flowId != null, "Either an application" + + " id or a cookie must be supplied"); + checkNotNull(selector != null, "Traffic selector cannot be null"); + checkNotNull(timeout != null || permanent != null, "Must either have " + + "a timeout or be permanent"); + checkNotNull(deviceId != null, "Must refer to a device"); + checkNotNull(priority != null, "Priority cannot be null"); + checkArgument(priority >= MIN_PRIORITY, "Priority cannot be less than " + + MIN_PRIORITY); + + return new DefaultFlowRule(deviceId, selector, treatment, priority, + flowId, permanent, timeout, tableId); + } + + private FlowId computeFlowId(ApplicationId appId) { + return FlowId.valueOf((((long) appId.id()) << 48) + | (hash() & 0xffffffffL)); + } + + private int hash() { + return Objects.hash(deviceId, priority, selector, tableId); + } + + } + + @Override + public FlowRuleExtPayLoad payLoad() { + return payLoad; + } + +} 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 new file mode 100644 index 00000000..f88c6bc3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java @@ -0,0 +1,365 @@ +/* + * Copyright 2014-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 com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableSet; +import org.onlab.packet.Ip6Address; +import org.onlab.packet.IpPrefix; +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.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * Default traffic selector implementation. + */ +public final class DefaultTrafficSelector implements TrafficSelector { + + private final Set criteria; + + private static final TrafficSelector EMPTY + = new DefaultTrafficSelector(Collections.emptySet()); + + /** + * Creates a new traffic selector with the specified criteria. + * + * @param criteria criteria + */ + private DefaultTrafficSelector(Set criteria) { + this.criteria = ImmutableSet.copyOf(criteria); + } + + @Override + public Set criteria() { + return criteria; + } + + @Override + public Criterion getCriterion(Criterion.Type type) { + for (Criterion c : criteria) { + if (c.type() == type) { + return c; + } + } + return null; + } + + @Override + public int hashCode() { + return criteria.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultTrafficSelector) { + DefaultTrafficSelector that = (DefaultTrafficSelector) obj; + return Objects.equals(criteria, that.criteria); + + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("criteria", criteria) + .toString(); + } + + /** + * Returns a new traffic selector builder. + * + * @return traffic selector builder + */ + public static TrafficSelector.Builder builder() { + return new Builder(); + } + + /** + * Returns an empty traffic selector. + * + * @return empty traffic selector + */ + public static TrafficSelector emptySelector() { + return EMPTY; + } + + /** + * Returns a new traffic selector builder primed to produce entities + * patterned after the supplied selector. + * + * @param selector base selector + * @return traffic selector builder + */ + public static TrafficSelector.Builder builder(TrafficSelector selector) { + return new Builder(selector); + } + + /** + * Builder of traffic selector entities. + */ + public static final class Builder implements TrafficSelector.Builder { + + private final Map selector = new HashMap<>(); + + private Builder() { + } + + private Builder(TrafficSelector selector) { + for (Criterion c : selector.criteria()) { + add(c); + } + } + + @Override + public Builder add(Criterion criterion) { + selector.put(criterion.type(), criterion); + return this; + } + + @Override + public Builder matchInPort(PortNumber port) { + return add(Criteria.matchInPort(port)); + } + + @Override + public Builder matchInPhyPort(PortNumber port) { + return add(Criteria.matchInPhyPort(port)); + } + + @Override + public Builder matchMetadata(long metadata) { + return add(Criteria.matchMetadata(metadata)); + } + + @Override + public Builder matchEthDst(MacAddress addr) { + return add(Criteria.matchEthDst(addr)); + } + + @Override + public Builder matchEthSrc(MacAddress addr) { + return add(Criteria.matchEthSrc(addr)); + } + + @Override + public Builder matchEthType(short ethType) { + return add(Criteria.matchEthType(ethType)); + } + + @Override + public Builder matchVlanId(VlanId vlanId) { + return add(Criteria.matchVlanId(vlanId)); + } + + @Override + public Builder matchVlanPcp(byte vlanPcp) { + return add(Criteria.matchVlanPcp(vlanPcp)); + } + + @Override + public Builder matchIPDscp(byte ipDscp) { + return add(Criteria.matchIPDscp(ipDscp)); + } + + @Override + public Builder matchIPEcn(byte ipEcn) { + return add(Criteria.matchIPEcn(ipEcn)); + } + + @Override + public Builder matchIPProtocol(byte proto) { + return add(Criteria.matchIPProtocol(proto)); + } + + @Override + public Builder matchIPSrc(IpPrefix ip) { + return add(Criteria.matchIPSrc(ip)); + } + + @Override + public Builder matchIPDst(IpPrefix ip) { + return add(Criteria.matchIPDst(ip)); + } + + @Deprecated + @Override + public Builder matchTcpSrc(short tcpPort) { + return matchTcpSrc(TpPort.tpPort(tcpPort)); + } + + @Override + public Builder matchTcpSrc(TpPort tcpPort) { + return add(Criteria.matchTcpSrc(tcpPort)); + } + + @Deprecated + @Override + public Builder matchTcpDst(short tcpPort) { + return matchTcpDst(TpPort.tpPort(tcpPort)); + } + + @Override + public Builder matchTcpDst(TpPort tcpPort) { + return add(Criteria.matchTcpDst(tcpPort)); + } + + @Deprecated + @Override + public Builder matchUdpSrc(short udpPort) { + return matchUdpSrc(TpPort.tpPort(udpPort)); + } + + @Override + public Builder matchUdpSrc(TpPort udpPort) { + return add(Criteria.matchUdpSrc(udpPort)); + } + + @Deprecated + @Override + public Builder matchUdpDst(short udpPort) { + return matchUdpDst(TpPort.tpPort(udpPort)); + } + + @Override + public Builder matchUdpDst(TpPort udpPort) { + return add(Criteria.matchUdpDst(udpPort)); + } + + @Deprecated + @Override + public Builder matchSctpSrc(short sctpPort) { + return matchSctpSrc(TpPort.tpPort(sctpPort)); + } + + @Override + public Builder matchSctpSrc(TpPort sctpPort) { + return add(Criteria.matchSctpSrc(sctpPort)); + } + + @Deprecated + @Override + public Builder matchSctpDst(short sctpPort) { + return matchSctpDst(TpPort.tpPort(sctpPort)); + } + + @Override + public Builder matchSctpDst(TpPort sctpPort) { + return add(Criteria.matchSctpDst(sctpPort)); + } + + @Override + public Builder matchIcmpType(byte icmpType) { + return add(Criteria.matchIcmpType(icmpType)); + } + + @Override + public Builder matchIcmpCode(byte icmpCode) { + return add(Criteria.matchIcmpCode(icmpCode)); + } + + @Override + public Builder matchIPv6Src(IpPrefix ip) { + return add(Criteria.matchIPv6Src(ip)); + } + + @Override + public Builder matchIPv6Dst(IpPrefix ip) { + return add(Criteria.matchIPv6Dst(ip)); + } + + @Override + public Builder matchIPv6FlowLabel(int flowLabel) { + return add(Criteria.matchIPv6FlowLabel(flowLabel)); + } + + @Override + public Builder matchIcmpv6Type(byte icmpv6Type) { + return add(Criteria.matchIcmpv6Type(icmpv6Type)); + } + + @Override + public Builder matchIcmpv6Code(byte icmpv6Code) { + return add(Criteria.matchIcmpv6Code(icmpv6Code)); + } + + @Override + public Builder matchIPv6NDTargetAddress(Ip6Address targetAddress) { + return add(Criteria.matchIPv6NDTargetAddress(targetAddress)); + } + + @Override + public Builder matchIPv6NDSourceLinkLayerAddress(MacAddress mac) { + return add(Criteria.matchIPv6NDSourceLinkLayerAddress(mac)); + } + + @Override + public Builder matchIPv6NDTargetLinkLayerAddress(MacAddress mac) { + return add(Criteria.matchIPv6NDTargetLinkLayerAddress(mac)); + } + + @Override + public Builder matchMplsLabel(MplsLabel mplsLabel) { + return add(Criteria.matchMplsLabel(mplsLabel)); + } + + @Override + public Builder matchMplsBos(boolean mplsBos) { + return add(Criteria.matchMplsLabel(mplsBos)); + } + + @Override + public TrafficSelector.Builder matchTunnelId(long tunnelId) { + return add(Criteria.matchTunnelId(tunnelId)); + } + + @Override + public Builder matchIPv6ExthdrFlags(short exthdrFlags) { + 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 new file mode 100644 index 00000000..5d18a9ad --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java @@ -0,0 +1,479 @@ +/* + * Copyright 2014-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 com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import org.onlab.packet.EthType; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.TpPort; +import org.onlab.packet.VlanId; +import org.onosproject.core.GroupId; +import org.onosproject.net.IndexedLambda; +import org.onosproject.net.PortNumber; +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; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default traffic treatment implementation. + */ +public final class DefaultTrafficTreatment implements TrafficTreatment { + + private final List immediate; + private final List deferred; + private final List all; + private final Instructions.TableTypeTransition table; + private final Instructions.MetadataInstruction meta; + + private final boolean hasClear; + + private static final DefaultTrafficTreatment EMPTY + = new DefaultTrafficTreatment(Collections.emptyList()); + private final Instructions.MeterInstruction meter; + + /** + * Creates a new traffic treatment from the specified list of instructions. + * + * @param immediate immediate instructions + */ + private DefaultTrafficTreatment(List immediate) { + this.immediate = ImmutableList.copyOf(checkNotNull(immediate)); + this.deferred = ImmutableList.of(); + this.all = this.immediate; + this.hasClear = false; + this.table = null; + this.meta = null; + this.meter = null; + } + + /** + * Creates a new traffic treatment from the specified list of instructions. + * + * @param deferred deferred instructions + * @param immediate immediate instructions + * @param table table transition instruction + * @param clear instruction to clear the deferred actions list + */ + private DefaultTrafficTreatment(List deferred, + List immediate, + Instructions.TableTypeTransition table, + boolean clear, + Instructions.MetadataInstruction meta, + Instructions.MeterInstruction meter) { + this.immediate = ImmutableList.copyOf(checkNotNull(immediate)); + this.deferred = ImmutableList.copyOf(checkNotNull(deferred)); + this.all = new ImmutableList.Builder() + .addAll(immediate) + .addAll(deferred) + .build(); + this.table = table; + this.meta = meta; + this.hasClear = clear; + this.meter = meter; + } + + @Override + public List deferred() { + return deferred; + } + + @Override + public List immediate() { + return immediate; + } + + @Override + public List allInstructions() { + return all; + } + + @Override + public Instructions.TableTypeTransition tableTransition() { + return table; + } + + @Override + public boolean clearedDeferred() { + return hasClear; + } + + @Override + public Instructions.MetadataInstruction writeMetadata() { + return meta; + } + + @Override + public Instructions.MeterInstruction metered() { + return meter; + } + + /** + * Returns a new traffic treatment builder. + * + * @return traffic treatment builder + */ + public static TrafficTreatment.Builder builder() { + return new Builder(); + } + + /** + * Returns an empty traffic treatment. + * + * @return empty traffic treatment + */ + public static TrafficTreatment emptyTreatment() { + return EMPTY; + } + + /** + * Returns a new traffic treatment builder primed to produce entities + * patterned after the supplied treatment. + * + * @param treatment base treatment + * @return traffic treatment builder + */ + public static TrafficTreatment.Builder builder(TrafficTreatment treatment) { + return new Builder(treatment); + } + + //FIXME: Order of instructions may affect hashcode + @Override + public int hashCode() { + return Objects.hash(immediate, deferred, table, meta); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultTrafficTreatment) { + DefaultTrafficTreatment that = (DefaultTrafficTreatment) obj; + return Objects.equals(immediate, that.immediate) && + Objects.equals(deferred, that.deferred) && + Objects.equals(table, that.table) && + Objects.equals(meta, that.meta); + + } + return false; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("immediate", immediate) + .add("deferred", deferred) + .add("transition", table == null ? "None" : table.toString()) + .add("cleared", hasClear) + .add("metadata", meta) + .toString(); + } + + /** + * Builds a list of treatments following the following order. + * Modifications -> Group -> Output (including drop) + */ + public static final class Builder implements TrafficTreatment.Builder { + + boolean clear = false; + + Instructions.TableTypeTransition table; + + Instructions.MetadataInstruction meta; + + Instructions.MeterInstruction meter; + + List deferred = Lists.newLinkedList(); + + List immediate = Lists.newLinkedList(); + + List current = immediate; + + + + // Creates a new builder + private Builder() { + } + + // Creates a new builder based off an existing treatment + private Builder(TrafficTreatment treatment) { + deferred(); + treatment.deferred().forEach(i -> add(i)); + + immediate(); + treatment.immediate().forEach(i -> add(i)); + + clear = treatment.clearedDeferred(); + } + + @Override + public Builder add(Instruction instruction) { + + switch (instruction.type()) { + case DROP: + case OUTPUT: + case GROUP: + case L0MODIFICATION: + case L2MODIFICATION: + case L3MODIFICATION: + case L4MODIFICATION: + current.add(instruction); + break; + case TABLE: + table = (Instructions.TableTypeTransition) instruction; + break; + case METADATA: + meta = (Instructions.MetadataInstruction) instruction; + break; + case METER: + meter = (Instructions.MeterInstruction) instruction; + default: + throw new IllegalArgumentException("Unknown instruction type: " + + instruction.type()); + } + + return this; + } + + @Override + public Builder drop() { + return add(Instructions.createDrop()); + } + + @Override + public Builder punt() { + return add(Instructions.createOutput(PortNumber.CONTROLLER)); + } + + @Override + public Builder setOutput(PortNumber number) { + return add(Instructions.createOutput(number)); + } + + @Override + public Builder setEthSrc(MacAddress addr) { + return add(Instructions.modL2Src(addr)); + } + + @Override + public Builder setEthDst(MacAddress addr) { + return add(Instructions.modL2Dst(addr)); + } + + @Override + public Builder setVlanId(VlanId id) { + return add(Instructions.modVlanId(id)); + } + + @Override + public Builder setVlanPcp(Byte pcp) { + return add(Instructions.modVlanPcp(pcp)); + } + + @Override + public Builder setIpSrc(IpAddress addr) { + return add(Instructions.modL3Src(addr)); + } + + @Override + public Builder setIpDst(IpAddress addr) { + return add(Instructions.modL3Dst(addr)); + } + + @Override + public Builder decNwTtl() { + return add(Instructions.decNwTtl()); + } + + @Override + public Builder copyTtlIn() { + return add(Instructions.copyTtlIn()); + } + + @Override + public Builder copyTtlOut() { + return add(Instructions.copyTtlOut()); + } + + @Override + public Builder pushMpls() { + return add(Instructions.pushMpls()); + } + + @Override + public Builder popMpls() { + return add(Instructions.popMpls()); + } + + @Override + public Builder popMpls(int etherType) { + return add(Instructions.popMpls(new EthType(etherType))); + } + + @Override + public Builder popMpls(EthType etherType) { + return add(Instructions.popMpls(etherType)); + } + + @Override + public Builder setMpls(MplsLabel mplsLabel) { + return add(Instructions.modMplsLabel(mplsLabel)); + } + + @Override + public Builder setMplsBos(boolean mplsBos) { + return add(Instructions.modMplsBos(mplsBos)); + } + + @Override + public Builder decMplsTtl() { + return add(Instructions.decMplsTtl()); + } + + @Deprecated + @Override + public Builder setLambda(short lambda) { + return add(Instructions.modL0Lambda(new IndexedLambda(lambda))); + } + + @Override + public Builder group(GroupId groupId) { + return add(Instructions.createGroup(groupId)); + } + + @Override + public TrafficTreatment.Builder meter(MeterId meterId) { + return add(Instructions.meterTraffic(meterId)); + } + + @Override + public Builder popVlan() { + return add(Instructions.popVlan()); + } + + @Override + public Builder pushVlan() { + 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)); + } + + @Override + public Builder immediate() { + current = immediate; + return this; + } + + @Override + public Builder deferred() { + current = deferred; + return this; + } + + @Override + public Builder wipeDeferred() { + clear = true; + return this; + } + + @Override + public Builder writeMetadata(long metadata, long metadataMask) { + return add(Instructions.writeMetadata(metadata, metadataMask)); + } + + @Override + public Builder setTunnelId(long tunnelId) { + return add(Instructions.modTunnelId(tunnelId)); + } + + @Deprecated + @Override + public TrafficTreatment.Builder setTcpSrc(short port) { + return setTcpSrc(TpPort.tpPort(port)); + } + + @Override + public TrafficTreatment.Builder setTcpSrc(TpPort port) { + return add(Instructions.modTcpSrc(port)); + } + + @Deprecated + @Override + public TrafficTreatment.Builder setTcpDst(short port) { + return setTcpDst(TpPort.tpPort(port)); + } + + @Override + public TrafficTreatment.Builder setTcpDst(TpPort port) { + return add(Instructions.modTcpDst(port)); + } + + @Deprecated + @Override + public TrafficTreatment.Builder setUdpSrc(short port) { + return setUdpSrc(TpPort.tpPort(port)); + } + + @Override + public TrafficTreatment.Builder setUdpSrc(TpPort port) { + return add(Instructions.modUdpSrc(port)); + } + + @Deprecated + @Override + public TrafficTreatment.Builder setUdpDst(short port) { + return setUdpDst(TpPort.tpPort(port)); + } + + @Override + public TrafficTreatment.Builder setUdpDst(TpPort port) { + return add(Instructions.modUdpDst(port)); + } + + @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(); + //} + return new DefaultTrafficTreatment(deferred, immediate, table, clear, meta, meter); + } + + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowEntry.java new file mode 100644 index 00000000..389b2142 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowEntry.java @@ -0,0 +1,102 @@ +/* + * Copyright 2014 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 generalized match & action pair to be applied to + * an infrastucture device. + */ +public interface FlowEntry extends FlowRule { + + + enum FlowEntryState { + + /** + * Indicates that this rule has been submitted for addition. + * Not necessarily in the flow table. + */ + PENDING_ADD, + + /** + * Rule has been added which means it is in the flow table. + */ + ADDED, + + /** + * Flow has been marked for removal, might still be in flow table. + */ + PENDING_REMOVE, + + /** + * Flow has been removed from flow table and can be purged. + */ + REMOVED, + + /** + * Indicates that the installation of this flow has failed. + */ + FAILED + } + + /** + * Returns the flow entry state. + * + * @return flow entry state + */ + FlowEntryState state(); + + /** + * Returns the number of milliseconds this flow rule has been applied. + * + * @return number of millis + */ + long life(); + + /** + * Returns the number of packets this flow rule has matched. + * + * @return number of packets + */ + long packets(); + + /** + * Returns the number of bytes this flow rule has matched. + * + * @return number of bytes + */ + long bytes(); + + // TODO: consider removing this attribute + /** + * When this flow entry was last deemed active. + * @return epoch time of last activity + */ + long lastSeen(); + + /** + * Indicates the error type. + * @return an integer value of the error + */ + int errType(); + + /** + * Indicates the error code. + * @return an integer value of the error + */ + int errCode(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowId.java new file mode 100644 index 00000000..52500f59 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowId.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014 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 com.google.common.base.Objects; + +/** + * Representation of a Flow ID. + */ +public final class FlowId { + + private final long flowid; + + private FlowId(long id) { + this.flowid = id; + } + + public static FlowId valueOf(long id) { + return new FlowId(id); + } + + public long value() { + return flowid; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (obj.getClass() == this.getClass()) { + FlowId that = (FlowId) obj; + return Objects.equal(this.flowid, that.flowid); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(this.flowid); + } +} 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 new file mode 100644 index 00000000..e446a9fe --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRule.java @@ -0,0 +1,265 @@ +/* + * Copyright 2014 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.core.ApplicationId; +import org.onosproject.core.GroupId; +import org.onosproject.net.DeviceId; + +/** + * Represents a generalized match & action pair to be applied to an + * infrastructure device. + */ +public interface FlowRule { + + static final int MAX_TIMEOUT = 60; + static final 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 + static 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. + * + * @return the flow ID + */ + FlowId id(); + + /** + * Returns the application id of this flow. + * + * @return an applicationId + */ + short appId(); + + /** + * Returns the group id of this flow. + * + * @return an groupId + */ + GroupId groupId(); + + /** + * Returns the flow rule priority given in natural order; higher numbers + * mean higher priorities. + * + * @return flow rule priority + */ + int priority(); + + /** + * Returns the identity of the device where this rule applies. + * + * @return device identifier + */ + DeviceId deviceId(); + + /** + * Returns the traffic selector that identifies what traffic this rule + * should apply to. + * + * @return traffic selector + */ + TrafficSelector selector(); + + /** + * Returns the traffic treatment that applies to selected traffic. + * + * @return traffic treatment + */ + TrafficTreatment treatment(); + + /** + * Returns the timeout for this flow requested by an application. + * + * @return integer value of the timeout + */ + int timeout(); + + /** + * Returns whether the flow is permanent i.e. does not time out. + * + * @return true if the flow is permanent, otherwise false + */ + boolean isPermanent(); + + /** + * Returns the table id for this rule. + * + * @return an integer. + */ + int tableId(); + + /** + * {@inheritDoc} + * + * Equality for flow rules only considers 'match equality'. This means that + * two flow rules with the same match conditions will be equal, regardless + * of the treatment or other characteristics of the flow. + * + * @param obj the reference object with which to compare. + * @return {@code true} if this object is the same as the obj + * argument; {@code false} otherwise. + */ + boolean equals(Object obj); + + /** + * Returns whether this flow rule is an exact match to the flow rule given + * in the argument. + *

+ * Exact match means that deviceId, priority, selector, + * tableId, flowId and treatment are equal. Note that this differs from + * the notion of object equality for flow rules, which does not consider the + * flowId or treatment when testing equality. + *

+ * + * @param rule other rule to match against + * @return true if the rules are an exact match, otherwise false + */ + boolean exactMatch(FlowRule rule); + + /** + * A flowrule builder. + */ + interface Builder { + + /** + * Assigns a cookie value to this flowrule. Mutually exclusive with the + * fromApp method. This method is intended to take a cookie value from + * the dataplane and not from the application. + * + * @param cookie a long value + * @return this + */ + Builder withCookie(long cookie); + + /** + * Assigns the application that built this flow rule to this object. + * The short value of the appId will be used as a basis for the + * cookie value computation. It is expected that application use this + * call to set their application id. + * + * @param appId an application id + * @return this + */ + Builder fromApp(ApplicationId appId); + + /** + * Sets the priority for this flow rule. + * + * @param priority an integer + * @return this + */ + Builder withPriority(int priority); + + /** + * Sets the deviceId for this flow rule. + * + * @param deviceId a device id + * @return this + */ + Builder forDevice(DeviceId deviceId); + + /** + * Sets the table id for this flow rule. Default value is 0. + * + * @param tableId an integer + * @return this + */ + Builder forTable(int tableId); + + /** + * Sets the selector (or match field) for this flow rule. + * + * @param selector a traffic selector + * @return this + */ + Builder withSelector(TrafficSelector selector); + + /** + * Sets the traffic treatment for this flow rule. + * + * @param treatment a traffic treatment + * @return this + */ + Builder withTreatment(TrafficTreatment treatment); + + /** + * Makes this rule permanent on the dataplane. + * + * @return this + */ + Builder makePermanent(); + + /** + * Makes this rule temporary and timeout after the specified amount + * of time. + * + * @param timeout an integer + * @return this + */ + Builder makeTemporary(int timeout); + + /** + * Builds a flow rule object. + * + * @return a flow rule. + */ + FlowRule build(); + + } + + /** + * Returns the third party original flow rule. + * + * @return FlowRuleExtPayLoad + */ + FlowRuleExtPayLoad payLoad(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchEntry.java new file mode 100644 index 00000000..455c6bd8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchEntry.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014-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.flow.FlowRuleBatchEntry.FlowRuleOperation; + +@Deprecated +/** + * @deprecated in Drake release - no longer a public API + */ +public class FlowRuleBatchEntry + extends BatchOperationEntry { + + private final Long id; // FIXME: consider using Optional + + public FlowRuleBatchEntry(FlowRuleOperation operator, FlowRule target) { + super(operator, target); + this.id = null; + } + + public FlowRuleBatchEntry(FlowRuleOperation operator, FlowRule target, Long id) { + super(operator, target); + this.id = id; + } + + public Long id() { + return id; + } + + public enum FlowRuleOperation { + ADD, + REMOVE, + MODIFY + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchEvent.java new file mode 100644 index 00000000..2e823c23 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchEvent.java @@ -0,0 +1,116 @@ +/* + * Copyright 2014-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.event.AbstractEvent; +import org.onosproject.net.DeviceId; + +@Deprecated +/** + * Describes flow rule batch event. + * + * @deprecated in Drake release - no longer a public API + */ +public final class FlowRuleBatchEvent extends AbstractEvent { + + + /** + * Type of flow rule events. + */ + public enum Type { + + // Request has been forwarded to MASTER Node + /** + * Signifies that a batch operation has been initiated. + */ + BATCH_OPERATION_REQUESTED, + + // MASTER Node has pushed the batch down to the Device + // (e.g., Received barrier reply) + /** + * Signifies that a batch operation has completed. + */ + BATCH_OPERATION_COMPLETED, + } + + private final CompletedBatchOperation result; + private final DeviceId deviceId; + + /** + * Constructs a new FlowRuleBatchEvent. + * + * @param request batch operation request + * @param deviceId the device this batch will be processed on + * @return event. + */ + public static FlowRuleBatchEvent requested(FlowRuleBatchRequest request, DeviceId deviceId) { + FlowRuleBatchEvent event = new FlowRuleBatchEvent(Type.BATCH_OPERATION_REQUESTED, request, deviceId); + return event; + } + + /** + * Constructs a new FlowRuleBatchEvent. + * @param request batch operation request. + * @param result completed batch operation result. + * @return event. + */ + public static FlowRuleBatchEvent completed(FlowRuleBatchRequest request, CompletedBatchOperation result) { + FlowRuleBatchEvent event = new FlowRuleBatchEvent(Type.BATCH_OPERATION_COMPLETED, request, result); + return event; + } + + /** + * Returns the result of this batch operation. + * @return batch operation result. + */ + public CompletedBatchOperation result() { + return result; + } + + /** + * Returns the deviceId for this batch. + * @return device id + */ + public DeviceId deviceId() { + return deviceId; + } + + /** + * Creates an event of a given type and for the specified flow rule batch. + * + * @param type flow rule batch event type + * @param request event flow rule batch subject + * @param result the result of the batch operation + */ + private FlowRuleBatchEvent(Type type, FlowRuleBatchRequest request, CompletedBatchOperation result) { + super(type, request); + this.result = result; + this.deviceId = result.deviceId(); + } + + /** + * Creates an event of a given type and for the specified flow rule batch. + * + * @param type flow rule batch event type + * @param request event flow rule batch subject + * @param deviceId the device id for this batch + */ + private FlowRuleBatchEvent(Type type, FlowRuleBatchRequest request, DeviceId deviceId) { + super(type, request); + this.result = null; + this.deviceId = deviceId; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchOperation.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchOperation.java new file mode 100644 index 00000000..35428f46 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchOperation.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014-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 java.util.Collection; + +@Deprecated +/** + * Class used with the flow subsystem to process per device + * batches. + * + * @deprecated in Drake release - no longer a public API + */ +public class FlowRuleBatchOperation + extends BatchOperation { + + /** + * This id is used to cary to id of the original + * FlowOperations and track where this batch operation + * came from. The id is unique cluster wide. + */ + private final long id; + private final DeviceId deviceId; + + public FlowRuleBatchOperation(Collection operations, + DeviceId deviceId, long flowOperationId) { + super(operations); + this.id = flowOperationId; + this.deviceId = deviceId; + } + + public DeviceId deviceId() { + return this.deviceId; + } + + public long id() { + return id; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchRequest.java new file mode 100644 index 00000000..0b0585b9 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleBatchRequest.java @@ -0,0 +1,59 @@ +/* + * Copyright 2014-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 com.google.common.collect.Lists; +import org.onosproject.net.DeviceId; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +@Deprecated +/** + * @deprecated in Drake release - no longer a public API + */ +public class FlowRuleBatchRequest { + + /** + * This id is used to carry to id of the original + * FlowOperations and track where this batch operation + * came from. The id is unique cluster wide. + */ + private final long batchId; + + private final Set ops; + + + public FlowRuleBatchRequest(long batchId, Set ops) { + this.batchId = batchId; + this.ops = Collections.unmodifiableSet(ops); + } + + public Set ops() { + return ops; + } + + public FlowRuleBatchOperation asBatchOperation(DeviceId deviceId) { + List entries = Lists.newArrayList(); + entries.addAll(ops); + return new FlowRuleBatchOperation(entries, deviceId, batchId); + } + + public long batchId() { + return batchId; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleEvent.java new file mode 100644 index 00000000..41ef1c8a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleEvent.java @@ -0,0 +1,78 @@ +/* + * Copyright 2014 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.event.AbstractEvent; + +/** + * Describes flow rule event. + */ +public class FlowRuleEvent extends AbstractEvent { + + /** + * Type of flow rule events. + */ + public enum Type { + /** + * Signifies that a new flow rule has been detected. + */ + RULE_ADDED, + + /** + * Signifies that a flow rule has been removed. + */ + RULE_REMOVED, + + /** + * Signifies that a rule has been updated. + */ + RULE_UPDATED, + + // internal event between Manager <-> Store + + /* + * Signifies that a request to add flow rule has been added to the store. + */ + RULE_ADD_REQUESTED, + /* + * Signifies that a request to remove flow rule has been added to the store. + */ + RULE_REMOVE_REQUESTED, + } + + /** + * Creates an event of a given type and for the specified flow rule and the + * current time. + * + * @param type flow rule event type + * @param flowRule event flow rule subject + */ + public FlowRuleEvent(Type type, FlowRule flowRule) { + super(type, flowRule); + } + + /** + * Creates an event of a given type and for the specified flow rule and time. + * + * @param type flow rule event type + * @param flowRule event flow rule subject + * @param time occurrence time + */ + public FlowRuleEvent(Type type, FlowRule flowRule, long time) { + super(type, flowRule, time); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleExtPayLoad.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleExtPayLoad.java new file mode 100644 index 00000000..8d36be49 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleExtPayLoad.java @@ -0,0 +1,67 @@ +package org.onosproject.net.flow; + +import static com.google.common.base.MoreObjects.toStringHelper; + +import java.util.Arrays; + +/** + * Represents for 3rd-party private original flow. + */ +public final class FlowRuleExtPayLoad { + private final byte[] payLoad; + + /** + * private constructor. + * + * @param payLoad private flow + */ + private FlowRuleExtPayLoad(byte[] payLoad) { + this.payLoad = payLoad; + } + + /** + * Creates a FlowRuleExtPayLoad. + * + * @param payLoad payload byte data + * @return FlowRuleExtPayLoad payLoad + */ + public static FlowRuleExtPayLoad flowRuleExtPayLoad(byte[] payLoad) { + return new FlowRuleExtPayLoad(payLoad); + } + + /** + * Returns private flow. + * + * @return payLoad private flow + */ + public byte[] payLoad() { + return payLoad; + } + + @Override + public int hashCode() { + return Arrays.hashCode(payLoad); + } + + public int hash() { + return Arrays.hashCode(payLoad); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof FlowRuleExtPayLoad) { + FlowRuleExtPayLoad that = (FlowRuleExtPayLoad) obj; + return Arrays.equals(payLoad, that.payLoad); + + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this).add("payLoad", payLoad).toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleListener.java new file mode 100644 index 00000000..1a6ef7d9 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleListener.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.event.EventListener; + +/** + * Entity capable of receiving flow rule related events. + */ +public interface FlowRuleListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperation.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperation.java new file mode 100644 index 00000000..82d43be8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperation.java @@ -0,0 +1,67 @@ +/* + * 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 com.google.common.base.MoreObjects; + +/** + * Representation of an operation on a flow rule table. + */ +public class FlowRuleOperation { + + /** + * Type of flow table operations. + */ + public enum Type { + ADD, + MODIFY, + REMOVE + } + + private final FlowRule rule; + private final Type type; + + public FlowRuleOperation(FlowRule rule, Type type) { + this.rule = rule; + this.type = type; + } + + /** + * Returns the type of operation. + * + * @return type + */ + public Type type() { + return type; + } + + /** + * Returns the flow rule. + * + * @return flow rule + */ + public FlowRule rule() { + return rule; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("rule", rule) + .add("type", type) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperations.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperations.java new file mode 100644 index 00000000..84e0b8be --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperations.java @@ -0,0 +1,181 @@ +/* + * 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 com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; + +import java.util.List; +import java.util.Set; + +import static org.onosproject.net.flow.FlowRuleOperation.Type.*; + +/** + * A batch of flow rule operations that are broken into stages. + * TODO move this up to parent's package + */ +public class FlowRuleOperations { + + private final List> stages; + private final FlowRuleOperationsContext callback; // TODO consider Optional + + private FlowRuleOperations(List> stages, + FlowRuleOperationsContext cb) { + this.stages = stages; + this.callback = cb; + } + + // kryo-constructor + protected FlowRuleOperations() { + this.stages = Lists.newArrayList(); + this.callback = null; + } + + /** + * Returns the flow rule operations as sets of stages that should be + * executed sequentially. + * + * @return flow rule stages + */ + public List> stages() { + return stages; + } + + /** + * Returns the callback for this batch of operations. + * + * @return callback + */ + public FlowRuleOperationsContext callback() { + return callback; + } + + /** + * Returns a new builder. + * + * @return new builder + */ + public static Builder builder() { + return new Builder(); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("stages", stages) + .toString(); + } + + /** + * A builder for constructing flow rule operations. + */ + public static final class Builder { + + private final ImmutableList.Builder> listBuilder = ImmutableList.builder(); + private ImmutableSet.Builder currentStage = ImmutableSet.builder(); + + // prevent use of the default constructor outside of this file; use the above method + private Builder() {} + + /** + * Appends a flow rule add to the current stage. + * + * @param flowRule flow rule + * @return this + */ + public Builder add(FlowRule flowRule) { + currentStage.add(new FlowRuleOperation(flowRule, ADD)); + return this; + } + + /** + * Appends an existing flow rule to the current stage. + * + * @param flowRuleOperation flow rule operation + * @return this + */ + public Builder operation(FlowRuleOperation flowRuleOperation) { + currentStage.add(flowRuleOperation); + return this; + } + + /** + * Appends a flow rule modify to the current stage. + * + * @param flowRule flow rule + * @return this + */ + public Builder modify(FlowRule flowRule) { + currentStage.add(new FlowRuleOperation(flowRule, MODIFY)); + return this; + } + + /** + * Appends a flow rule remove to the current stage. + * + * @param flowRule flow rule + * @return this + */ + // FIXME this is confusing, consider renaming + public Builder remove(FlowRule flowRule) { + currentStage.add(new FlowRuleOperation(flowRule, REMOVE)); + return this; + } + + /** + * Closes the current stage. + */ + private void closeStage() { + ImmutableSet stage = currentStage.build(); + if (!stage.isEmpty()) { + listBuilder.add(stage); + } + } + + /** + * Closes the current stage and starts a new one. + * + * @return this + */ + public Builder newStage() { + closeStage(); + currentStage = ImmutableSet.builder(); + return this; + } + + /** + * Builds the immutable flow rule operations. + * + * @return flow rule operations + */ + public FlowRuleOperations build() { + return build(null); + } + + /** + * Builds the immutable flow rule operations. + * + * @param cb the callback to call when this operation completes + * @return flow rule operations + */ + public FlowRuleOperations build(FlowRuleOperationsContext cb) { + closeStage(); + return new FlowRuleOperations(listBuilder.build(), cb); + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperationsContext.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperationsContext.java new file mode 100644 index 00000000..c405b129 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperationsContext.java @@ -0,0 +1,28 @@ +/* + * 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; + +/** + * The context of a flow rule operations that will become the subject of + * the notification. + * + * Implementations of this class must be serializable. + */ +public interface FlowRuleOperationsContext { + // TODO we might also want to execute a method on behalf of the app + default void onSuccess(FlowRuleOperations ops){} + default void onError(FlowRuleOperations ops){} +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProvider.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProvider.java new file mode 100644 index 00000000..ac2895eb --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProvider.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014-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.core.ApplicationId; +import org.onosproject.net.provider.Provider; + +/** + * Abstraction of a flow rule provider. + */ +public interface FlowRuleProvider extends Provider { + + /** + * Instructs the provider to apply the specified flow rules to their + * respective devices. + * @param flowRules one or more flow rules + * throws SomeKindOfException that indicates which ones were applied and + * which ones failed + */ + void applyFlowRule(FlowRule... flowRules); + + /** + * Instructs the provider to remove the specified flow rules to their + * respective devices. + * @param flowRules one or more flow rules + * throws SomeKindOfException that indicates which ones were applied and + * which ones failed + */ + void removeFlowRule(FlowRule... flowRules); + + /** + * Removes rules by their id. + * @param id the id to remove + * @param flowRules one or more flow rules + */ + void removeRulesById(ApplicationId id, FlowRule... flowRules); + + /** + * Installs a batch of flow rules. Each flowrule is associated to an + * operation which results in either addition, removal or modification. + * @param batch a batch of flow rules + */ + void executeBatch(FlowRuleBatchOperation batch); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderRegistry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderRegistry.java new file mode 100644 index 00000000..7e317c01 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderRegistry.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 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.provider.ProviderRegistry; + +/** + * Abstraction for a flow rule provider registry. + */ +public interface FlowRuleProviderRegistry + extends ProviderRegistry { +} 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 new file mode 100644 index 00000000..8a36a921 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleProviderService.java @@ -0,0 +1,52 @@ +/* + * Copyright 2014-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 org.onosproject.net.provider.ProviderService; + +/** + * Service through which flow rule providers can inject information into + * the core. + */ +public interface FlowRuleProviderService extends ProviderService { + + /** + * Signals that a flow rule that was previously installed has been removed. + * + * @param flowEntry removed flow entry + */ + void flowRemoved(FlowEntry flowEntry); + + /** + * Pushes the collection of flow entries currently applied on the given + * device. + * + * @param deviceId device identifier + * @param flowEntries collection of flow rules + */ + void pushFlowMetrics(DeviceId deviceId, Iterable flowEntries); + + /** + * Indicates to the core that the requested batch operation has + * been completed. + * + * @param batchId the batch which was processed + * @param operation the resulting outcome of the operation + */ + void batchOperationCompleted(long batchId, CompletedBatchOperation operation); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java new file mode 100644 index 00000000..e2971158 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java @@ -0,0 +1,107 @@ +/* + * Copyright 2014-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.core.ApplicationId; +import org.onosproject.event.ListenerService; +import org.onosproject.net.DeviceId; + +/** + * Service for injecting flow rules into the environment and for obtaining + * information about flow rules already in the environment. This implements + * semantics of a distributed authoritative flow table where the master copy + * of the flow rules lies with the controller and the devices hold only the + * 'cached' copy. + */ +public interface FlowRuleService + extends ListenerService { + + /** + * The topic used for obtaining globally unique ids. + */ + static String FLOW_OP_TOPIC = "flow-ops-ids"; + + /** + * Returns the number of flow rules in the system. + * + * @return flow rule count + */ + int getFlowRuleCount(); + + /** + * Returns the collection of flow entries applied on the specified device. + * This will include flow rules which may not yet have been applied to + * the device. + * + * @param deviceId device identifier + * @return collection of flow rules + */ + Iterable getFlowEntries(DeviceId deviceId); + + // TODO: add createFlowRule factory method and execute operations method + + /** + * Applies the specified flow rules onto their respective devices. These + * flow rules will be retained by the system and re-applied anytime the + * device reconnects to the controller. + * + * @param flowRules one or more flow rules + */ + void applyFlowRules(FlowRule... flowRules); + + /** + * Removes the specified flow rules from their respective devices. If the + * device is not presently connected to the controller, these flow will + * be removed once the device reconnects. + * + * @param flowRules one or more flow rules + * throws SomeKindOfException that indicates which ones were removed and + * which ones failed + */ + void removeFlowRules(FlowRule... flowRules); + + /** + * Removes all rules by id. + * + * @param appId id to remove + */ + void removeFlowRulesById(ApplicationId appId); + + /** + * Returns a list of rules with this application id. + * + * @param id the id to look up + * @return collection of flow rules + */ + Iterable getFlowRulesById(ApplicationId id); + + /** + * Returns a list of rules filterd by application and group id. + * + * @param appId the application id to lookup + * @param groupId the groupid to lookup + * @return collection of flow rules + */ + Iterable getFlowRulesByGroupId(ApplicationId appId, short groupId); + + /** + * Applies a batch operation of FlowRules. + * + * @param ops batch operation to apply + */ + void apply(FlowRuleOperations ops); + +} 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 new file mode 100644 index 00000000..cece9893 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java @@ -0,0 +1,96 @@ +/* + * Copyright 2014-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 org.onosproject.store.Store; + +/** + * Manages inventory of flow rules; not intended for direct use. + */ +public interface FlowRuleStore extends Store { + + /** + * Returns the number of flow rule in the store. + * + * @return number of flow rules + */ + int getFlowRuleCount(); + + /** + * Returns the stored flow. + * + * @param rule the rule to look for + * @return a flow rule + */ + FlowEntry getFlowEntry(FlowRule rule); + + /** + * Returns the flow entries associated with a device. + * + * @param deviceId the device ID + * @return the flow entries + */ + Iterable getFlowEntries(DeviceId deviceId); + + /** + * // TODO: Better description of method behavior. + * Stores a new flow rule without generating events. + * + * @param rule the flow rule to add + * @deprecated in Cardinal Release + */ + @Deprecated + void storeFlowRule(FlowRule rule); + + /** + * Stores a batch of flow rules. + * + * @param batchOperation batch of flow rules. + * A batch can contain flow rules for a single device only. + * + */ + void storeBatch(FlowRuleBatchOperation batchOperation); + + /** + * Invoked on the completion of a storeBatch operation. + * + * @param event flow rule batch event + */ + void batchOperationComplete(FlowRuleBatchEvent event); + + /** + * Marks a flow rule for deletion. Actual deletion will occur + * when the provider indicates that the flow has been removed. + * + * @param rule the flow rule to delete + */ + void deleteFlowRule(FlowRule rule); + + /** + * Stores a new flow rule, or updates an existing entry. + * + * @param rule the flow rule to add or update + * @return flow_added event, or null if just an update + */ + FlowRuleEvent addOrUpdateFlowRule(FlowEntry rule); + + /** + * @param rule the flow entry to remove + * @return flow_removed event, or null if nothing removed + */ + FlowRuleEvent removeFlowRule(FlowEntry rule); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStoreDelegate.java new file mode 100644 index 00000000..c4ddb129 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStoreDelegate.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.store.StoreDelegate; + +/** + * Flow rule store delegate abstraction. + */ +public interface FlowRuleStoreDelegate extends StoreDelegate { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/StoredFlowEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/StoredFlowEntry.java new file mode 100644 index 00000000..dc0c3395 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/StoredFlowEntry.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014 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; + + +public interface StoredFlowEntry extends FlowEntry { + + /** + * Sets the last active epoch time. + */ + void setLastSeen(); + + /** + * Sets the new state for this entry. + * @param newState new flow entry state. + */ + void setState(FlowEntryState newState); + + /** + * Sets how long this entry has been entered in the system. + * @param life epoch time + */ + void setLife(long life); + + /** + * Number of packets seen by this entry. + * @param packets a long value + */ + void setPackets(long packets); + + /** + * Number of bytes seen by this rule. + * @param bytes a long value + */ + void setBytes(long bytes); + +} 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 new file mode 100644 index 00000000..f2de9a0f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java @@ -0,0 +1,420 @@ +/* + * Copyright 2014-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 java.util.Set; + +import org.onlab.packet.Ip6Address; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.TpPort; +import org.onlab.packet.VlanId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.DefaultTrafficSelector.Builder; +import org.onosproject.net.flow.criteria.Criterion; + +/** + * Abstraction of a slice of network traffic. + */ +public interface TrafficSelector { + + /** + * Returns selection criteria as an ordered list. + * + * @return list of criteria + */ + Set criteria(); + + /** + * Returns the selection criterion for a particular type, if it exists in + * this traffic selector. + * + * @param type criterion type to look up + * @return the criterion of the specified type if one exists, otherwise null + */ + Criterion getCriterion(Criterion.Type type); + + /** + * Builder of traffic selector entities. + */ + interface Builder { + + /** + * Adds a traffic selection criterion. If a same type criterion has + * already been added, it will be replaced by this one. + * + * @param criterion new criterion + * @return self + */ + Builder add(Criterion criterion); + + /** + * Matches an inport. + * + * @param port the inport + * @return a selection builder + */ + Builder matchInPort(PortNumber port); + + /** + * Matches a physical inport. + * + * @param port the physical inport + * @return a selection builder + */ + Builder matchInPhyPort(PortNumber port); + + /** + * Matches a metadata. + * + * @param metadata the metadata + * @return a selection builder + */ + Builder matchMetadata(long metadata); + + /** + * Matches a l2 dst address. + * + * @param addr a l2 address + * @return a selection builder + */ + Builder matchEthDst(MacAddress addr); + + /** + * Matches a l2 src address. + * + * @param addr a l2 address + * @return a selection builder + */ + Builder matchEthSrc(MacAddress addr); + + /** + * Matches the ethernet type. + * + * @param ethType an ethernet type + * @return a selection builder + */ + Builder matchEthType(short ethType); + + /** + * Matches the vlan id. + * + * @param vlanId a vlan id + * @return a selection builder + */ + Builder matchVlanId(VlanId vlanId); + + /** + * Matches a vlan priority. + * + * @param vlanPcp a vlan priority + * @return a selection builder + */ + Builder matchVlanPcp(byte vlanPcp); + + /** + * Matches an IP DSCP (6 bits in ToS field). + * + * @param ipDscp an IP DSCP value + * @return a selection builder + */ + Builder matchIPDscp(byte ipDscp); + + /** + * Matches an IP ECN (2 bits in ToS field). + * + * @param ipEcn an IP ECN value + * @return a selection builder + */ + Builder matchIPEcn(byte ipEcn); + + /** + * Matches the l3 protocol. + * + * @param proto a l3 protocol + * @return a selection builder + */ + Builder matchIPProtocol(byte proto); + + /** + * Matches a l3 IPv4 address. + * + * @param ip a l3 address + * @return a selection builder + */ + Builder matchIPSrc(IpPrefix ip); + + /** + * Matches a l3 IPv4 address. + * + * @param ip a l3 address + * @return a selection builder + */ + Builder matchIPDst(IpPrefix ip); + + /** + * Matches a TCP source port number. + * + * @param tcpPort a TCP source port number + * @return a selection builder + * @deprecated in Drake release + */ + @Deprecated + Builder matchTcpSrc(short tcpPort); + + /** + * Matches a TCP source port number. + * + * @param tcpPort a TCP source port number + * @return a selection builder + */ + Builder matchTcpSrc(TpPort tcpPort); + + /** + * Matches a TCP destination port number. + * + * @param tcpPort a TCP destination port number + * @return a selection builder + * @deprecated in Drake release + */ + @Deprecated + Builder matchTcpDst(short tcpPort); + + /** + * Matches a TCP destination port number. + * + * @param tcpPort a TCP destination port number + * @return a selection builder + */ + Builder matchTcpDst(TpPort tcpPort); + + /** + * Matches an UDP source port number. + * + * @param udpPort an UDP source port number + * @return a selection builder + * @deprecated in Drake release + */ + @Deprecated + Builder matchUdpSrc(short udpPort); + + /** + * Matches an UDP source port number. + * + * @param udpPort an UDP source port number + * @return a selection builder + */ + Builder matchUdpSrc(TpPort udpPort); + + /** + * Matches an UDP destination port number. + * + * @param udpPort an UDP destination port number + * @return a selection builder + * @deprecated in Drake release + */ + @Deprecated + Builder matchUdpDst(short udpPort); + + /** + * Matches an UDP destination port number. + * + * @param udpPort an UDP destination port number + * @return a selection builder + */ + Builder matchUdpDst(TpPort udpPort); + + /** + * Matches a SCTP source port number. + * + * @param sctpPort a SCTP source port number + * @return a selection builder + * @deprecated in Drake release + */ + @Deprecated + Builder matchSctpSrc(short sctpPort); + + /** + * Matches a SCTP source port number. + * + * @param sctpPort a SCTP source port number + * @return a selection builder + */ + Builder matchSctpSrc(TpPort sctpPort); + + /** + * Matches a SCTP destination port number. + * + * @param sctpPort a SCTP destination port number + * @return a selection builder + * @deprecated in Drake release + */ + @Deprecated + Builder matchSctpDst(short sctpPort); + + /** + * Matches a SCTP destination port number. + * + * @param sctpPort a SCTP destination port number + * @return a selection builder + */ + Builder matchSctpDst(TpPort sctpPort); + + /** + * Matches an ICMP type. + * + * @param icmpType an ICMP type + * @return a selection builder + */ + Builder matchIcmpType(byte icmpType); + + /** + * Matches an ICMP code. + * + * @param icmpCode an ICMP code + * @return a selection builder + */ + Builder matchIcmpCode(byte icmpCode); + + /** + * Matches a l3 IPv6 address. + * + * @param ip a l3 IPv6 address + * @return a selection builder + */ + Builder matchIPv6Src(IpPrefix ip); + + /** + * Matches a l3 IPv6 address. + * + * @param ip a l3 IPv6 address + * @return a selection builder + */ + Builder matchIPv6Dst(IpPrefix ip); + + /** + * Matches an IPv6 flow label. + * + * @param flowLabel an IPv6 flow label + * @return a selection builder + */ + Builder matchIPv6FlowLabel(int flowLabel); + + /** + * Matches an ICMPv6 type. + * + * @param icmpv6Type an ICMPv6 type + * @return a selection builder + */ + Builder matchIcmpv6Type(byte icmpv6Type); + + /** + * Matches an ICMPv6 code. + * + * @param icmpv6Code an ICMPv6 code + * @return a selection builder + */ + Builder matchIcmpv6Code(byte icmpv6Code); + + /** + * Matches an IPv6 Neighbor Discovery target address. + * + * @param targetAddress an IPv6 Neighbor Discovery target address + * @return a selection builder + */ + Builder matchIPv6NDTargetAddress(Ip6Address targetAddress); + + /** + * Matches an IPv6 Neighbor Discovery source link-layer address. + * + * @param mac an IPv6 Neighbor Discovery source link-layer address + * @return a selection builder + */ + Builder matchIPv6NDSourceLinkLayerAddress(MacAddress mac); + + /** + * Matches an IPv6 Neighbor Discovery target link-layer address. + * + * @param mac an IPv6 Neighbor Discovery target link-layer address + * @return a selection builder + */ + Builder matchIPv6NDTargetLinkLayerAddress(MacAddress mac); + + /** + * Matches on a MPLS label. + * + * @param mplsLabel a MPLS label. + * @return a selection builder + */ + Builder matchMplsLabel(MplsLabel mplsLabel); + + /** + * Matches on a MPLS Bottom-of-Stack indicator bit. + * + * @param mplsBos boolean value indicating BOS=1 (true) or BOS=0 (false). + * @return a selection builder + */ + Builder matchMplsBos(boolean mplsBos); + + /** + * Matches a tunnel id. + * + * @param tunnelId a tunnel id + * @return a selection builder + */ + Builder matchTunnelId(long tunnelId); + + /** + * Matches on IPv6 Extension Header pseudo-field flags. + * + * @param exthdrFlags the IPv6 Extension Header pseudo-field flags + * @return a selection builder + */ + 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. + * + * @return traffic selector + */ + TrafficSelector build(); + } +} 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 new file mode 100644 index 00000000..1ce669c2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java @@ -0,0 +1,431 @@ +/* + * Copyright 2014-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.onlab.packet.EthType; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.TpPort; +import org.onlab.packet.VlanId; +import org.onosproject.core.GroupId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.Instructions; +import org.onosproject.net.meter.MeterId; + +import java.util.List; + +/** + * Abstraction of network traffic treatment. + */ +public interface TrafficTreatment { + + /** + * Returns the list of treatment instructions that will be applied + * further down the pipeline. + * @return list of treatment instructions + */ + List deferred(); + + /** + * Returns the list of treatment instructions that will be applied + * immediately. + * @return list of treatment instructions + */ + List immediate(); + + /** + * Returns the list of all instructions in the treatment, both immediate and + * deferred. + * + * @return list of treatment instructions + */ + List allInstructions(); + + /** + * Returns the next table in the pipeline. + * @return a table transition; may be null. + */ + Instructions.TableTypeTransition tableTransition(); + + /** + * Whether the deferred treatment instructions will be cleared + * by the device. + * @return a boolean + */ + boolean clearedDeferred(); + + /** + * Returns the metadata instruction if there is one. + * + * @return a metadata instruction that may be null + */ + Instructions.MetadataInstruction writeMetadata(); + + /** + * Returns the meter instruction if there is one. + * + * @return a meter instruction that may be null + */ + Instructions.MeterInstruction metered(); + + /** + * Builder of traffic treatment entities. + */ + interface Builder { + + /** + * Adds an instruction to the builder. + * + * @param instruction an instruction + * @return a treatment builder + */ + Builder add(Instruction instruction); + + /** + * Adds a drop instruction. + * + * @return a treatment builder + */ + Builder drop(); + + /** + * Adds a punt-to-controller instruction. + * + * @return a treatment builder + */ + Builder punt(); + + /** + * Set the output port. + * + * @param number the out port + * @return a treatment builder + */ + Builder setOutput(PortNumber number); + + /** + * Sets the src l2 address. + * + * @param addr a macaddress + * @return a treatment builder + */ + Builder setEthSrc(MacAddress addr); + + /** + * Sets the dst l2 address. + * + * @param addr a macaddress + * @return a treatment builder + */ + Builder setEthDst(MacAddress addr); + + /** + * Sets the vlan id. + * + * @param id a vlanid + * @return a treatment builder + */ + Builder setVlanId(VlanId id); + + /** + * Sets the vlan priority. + * + * @param pcp a vlan priority + * @return a treatment builder + */ + Builder setVlanPcp(Byte pcp); + + /** + * Sets the src l3 address. + * + * @param addr an ip + * @return a treatment builder + */ + Builder setIpSrc(IpAddress addr); + + /** + * Sets the dst l3 address. + * + * @param addr an ip + * @return a treatment builder + */ + Builder setIpDst(IpAddress addr); + + /** + * Decrement the TTL in IP header by one. + * + * @return a treatment builder + */ + Builder decNwTtl(); + + /** + * Copy the TTL to outer protocol layer. + * + * @return a treatment builder + */ + Builder copyTtlOut(); + + /** + * Copy the TTL to inner protocol layer. + * + * @return a treatment builder + */ + Builder copyTtlIn(); + + /** + * Push MPLS ether type. + * + * @return a treatment builder. + */ + Builder pushMpls(); + + /** + * Pops MPLS ether type. + * + * @return a treatment builder. + */ + Builder popMpls(); + + /** + * Pops MPLS ether type and set the new ethertype. + * + * @param etherType an ether type + * @return a treatment builder. + * @deprecated in Drake Release + */ + @Deprecated + Builder popMpls(int etherType); + + /** + * Pops MPLS ether type and set the new ethertype. + * + * @param etherType an ether type + * @return a treatment builder. + */ + Builder popMpls(EthType etherType); + + /** + * Sets the mpls label. + * + * @param mplsLabel MPLS label. + * @return a treatment builder. + */ + Builder setMpls(MplsLabel mplsLabel); + + /** + * Sets the mpls bottom-of-stack indicator bit. + * + * @param mplsBos boolean to set BOS=1 (true) or BOS=0 (false). + * @return a treatment builder. + */ + Builder setMplsBos(boolean mplsBos); + + /** + * Decrement MPLS TTL. + * + * @return a treatment builder + */ + Builder decMplsTtl(); + + /** + * Sets the optical channel ID or lambda. + * + * @param lambda optical channel ID + * @return a treatment builder + * @deprecated in Drake Release + */ + @Deprecated + Builder setLambda(short lambda); + + /** + * Sets the group ID. + * + * @param groupId group ID + * @return a treatment builder + */ + Builder group(GroupId groupId); + + /** + * Sets a meter to be used by this flow. + * + * @param meterId a meter id + * @return a treatment builder + */ + 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. + * + * @param tableId the table table + * @return a treatement builder + */ + Builder transition(Integer tableId); + + + /** + * Pops outermost VLAN tag. + * + * @return a treatment builder. + */ + Builder popVlan(); + + /** + * Pushes a new VLAN tag. + * + * @return a treatment builder. + */ + Builder pushVlan(); + + /** + * Any instructions preceded by this method call will be deferred. + * @return a treatment builder + */ + Builder deferred(); + + /** + * Any instructions preceded by this method call will be immediate. + * @return a treatment builder + */ + Builder immediate(); + + + /** + * Instructs the device to clear the deferred instructions set. + * @return a treatment builder + */ + Builder wipeDeferred(); + + /** + * Writes metadata to associate with a packet. + *
+         * {@code
+         * new_metadata = (old_metadata &  ̃mask) | (value & mask)
+         * }
+         * 
+ * + * @param value the metadata to write + * @param mask the masked bits for the value + * @return a treatment builder + */ + Builder writeMetadata(long value, long mask); + + /** + * Sets the tunnel id. + * + * @param tunnelId a tunnel id. + * @return a treatment builder. + */ + Builder setTunnelId(long tunnelId); + + /** + * Sets the src TCP port. + * + * @param port a port number + * @return a treatment builder + * @deprecated in Drake release + */ + @Deprecated + Builder setTcpSrc(short port); + + /** + * Sets the src TCP port. + * + * @param port a port number + * @return a treatment builder + */ + Builder setTcpSrc(TpPort port); + + /** + * Sets the dst TCP port. + * + * @param port a port number + * @return a treatment builder + * @deprecated in Drake release + */ + @Deprecated + Builder setTcpDst(short port); + + /** + * Sets the dst TCP port. + * + * @param port a port number + * @return a treatment builder + */ + Builder setTcpDst(TpPort port); + + /** + * Sets the src UDP port. + * + * @param port a port number + * @return a treatment builder + * @deprecated in Drake release + */ + @Deprecated + Builder setUdpSrc(short port); + + /** + * Sets the src UDP port. + * + * @param port a port number + * @return a treatment builder + */ + Builder setUdpSrc(TpPort port); + + /** + * Sets the dst UDP port. + * + * @param port a port number + * @return a treatment builder + * @deprecated in Drake release + */ + @Deprecated + Builder setUdpDst(short port); + + /** + * Sets the dst UDP port. + * + * @param port a port number + * @return a treatment builder + */ + Builder setUdpDst(TpPort port); + + /** + * Builds an immutable traffic treatment descriptor. + *

+ * If the treatment is empty when build() is called, it will add a default + * drop rule automatically. For a treatment that is actually empty, use + * {@link org.onosproject.net.flow.DefaultTrafficTreatment#emptyTreatment}. + *

+ * + * @return traffic treatment + */ + TrafficTreatment build(); + + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Treatment.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Treatment.java new file mode 100644 index 00000000..a77079ce --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/Treatment.java @@ -0,0 +1,36 @@ +/* + * Copyright 2014 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.PortNumber; + +/** + * Abstraction of different kinds of treatment that can be applied to an + * outbound packet. + */ +public interface Treatment { + + // TODO: implement these later: modifications, group + // TODO: elsewhere provide factory methods for some default treatments + + /** + * Returns the port number where the packet should be emitted. + * + * @return output port number + */ + PortNumber output(); + +} 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 new file mode 100644 index 00000000..0252cfbc --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java @@ -0,0 +1,527 @@ +/* + * Copyright 2014-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.criteria; + +import org.onlab.packet.EthType; +import org.onlab.packet.Ip6Address; +import org.onlab.packet.IpPrefix; +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.Lambda; +import org.onosproject.net.OchSignal; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.criteria.Criterion.Type; +import org.onosproject.net.OchSignalType; + +/** + * Factory class to create various traffic selection criteria. + */ +public final class Criteria { + + //TODO: incomplete type implementation. Need to implement complete list from Criterion + + // Ban construction + private Criteria() { + } + + /** + * Creates a match on IN_PORT field using the specified value. + * + * @param port inport value + * @return match criterion + */ + public static Criterion matchInPort(PortNumber port) { + return new PortCriterion(port, Type.IN_PORT); + } + + /** + * Creates a match on IN_PHY_PORT field using the specified value. + * + * @param port inport value + * @return match criterion + */ + public static Criterion matchInPhyPort(PortNumber port) { + return new PortCriterion(port, Type.IN_PHY_PORT); + } + + /** + * Creates a match on METADATA field using the specified value. + * + * @param metadata metadata value (64 bits data) + * @return match criterion + */ + public static Criterion matchMetadata(long metadata) { + return new MetadataCriterion(metadata); + } + + /** + * Creates a match on ETH_DST field using the specified value. This value + * may be a wildcard mask. + * + * @param mac MAC address value or wildcard mask + * @return match criterion + */ + public static Criterion matchEthDst(MacAddress mac) { + return new EthCriterion(mac, Type.ETH_DST); + } + + /** + * Creates a match on ETH_SRC field using the specified value. This value + * may be a wildcard mask. + * + * @param mac MAC address value or wildcard mask + * @return match criterion + */ + public static Criterion matchEthSrc(MacAddress mac) { + return new EthCriterion(mac, Type.ETH_SRC); + } + + /** + * Creates a match on ETH_TYPE field using the specified value. + * + * @param ethType eth type value (16 bits unsigned integer) + * @return match criterion + */ + public static Criterion matchEthType(int ethType) { + return new EthTypeCriterion(ethType); + } + + /** + * Creates a match on ETH_TYPE field using the specified value. + * + * @param ethType eth type value + * @return match criterion + */ + public static Criterion matchEthType(EthType ethType) { + return new EthTypeCriterion(ethType); + } + + /** + * Creates a match on VLAN ID field using the specified value. + * + * @param vlanId vlan id value + * @return match criterion + */ + public static Criterion matchVlanId(VlanId vlanId) { + return new VlanIdCriterion(vlanId); + } + + /** + * Creates a match on VLAN PCP field using the specified value. + * + * @param vlanPcp vlan pcp value (3 bits) + * @return match criterion + */ + public static Criterion matchVlanPcp(byte vlanPcp) { + return new VlanPcpCriterion(vlanPcp); + } + + /** + * Creates a match on IP DSCP field using the specified value. + * + * @param ipDscp ip dscp value (6 bits) + * @return match criterion + */ + public static Criterion matchIPDscp(byte ipDscp) { + return new IPDscpCriterion(ipDscp); + } + + /** + * Creates a match on IP ECN field using the specified value. + * + * @param ipEcn ip ecn value (2 bits) + * @return match criterion + */ + public static Criterion matchIPEcn(byte ipEcn) { + return new IPEcnCriterion(ipEcn); + } + + /** + * Creates a match on IP proto field using the specified value. + * + * @param proto ip protocol value (8 bits unsigned integer) + * @return match criterion + */ + public static Criterion matchIPProtocol(short proto) { + return new IPProtocolCriterion(proto); + } + + /** + * Creates a match on IPv4 source field using the specified value. + * + * @param ip ipv4 source value + * @return match criterion + */ + public static Criterion matchIPSrc(IpPrefix ip) { + return new IPCriterion(ip, Type.IPV4_SRC); + } + + /** + * Creates a match on IPv4 destination field using the specified value. + * + * @param ip ipv4 source value + * @return match criterion + */ + public static Criterion matchIPDst(IpPrefix ip) { + return new IPCriterion(ip, Type.IPV4_DST); + } + + /** + * Creates a match on TCP source port field using the specified value. + * + * @param tcpPort TCP source port + * @return match criterion + * @deprecated in Drake release + */ + @Deprecated + public static Criterion matchTcpSrc(short tcpPort) { + return new TcpPortCriterion(TpPort.tpPort(tcpPort), Type.TCP_SRC); + } + + /** + * Creates a match on TCP source port field using the specified value. + * + * @param tcpPort TCP source port + * @return match criterion + */ + public static Criterion matchTcpSrc(TpPort tcpPort) { + return new TcpPortCriterion(tcpPort, Type.TCP_SRC); + } + + /** + * Creates a match on TCP destination port field using the specified value. + * + * @param tcpPort TCP destination port + * @return match criterion + * @deprecated in Drake release + */ + @Deprecated + public static Criterion matchTcpDst(short tcpPort) { + return new TcpPortCriterion(TpPort.tpPort(tcpPort), Type.TCP_DST); + } + + /** + * Creates a match on TCP destination port field using the specified value. + * + * @param tcpPort TCP destination port + * @return match criterion + */ + public static Criterion matchTcpDst(TpPort tcpPort) { + return new TcpPortCriterion(tcpPort, Type.TCP_DST); + } + + /** + * Creates a match on UDP source port field using the specified value. + * + * @param udpPort UDP source port + * @return match criterion + * @deprecated in Drake release + */ + @Deprecated + public static Criterion matchUdpSrc(short udpPort) { + return new UdpPortCriterion(TpPort.tpPort(udpPort), Type.UDP_SRC); + } + + /** + * Creates a match on UDP source port field using the specified value. + * + * @param udpPort UDP source port + * @return match criterion + */ + public static Criterion matchUdpSrc(TpPort udpPort) { + return new UdpPortCriterion(udpPort, Type.UDP_SRC); + } + + /** + * Creates a match on UDP destination port field using the specified value. + * + * @param udpPort UDP destination port + * @return match criterion + * @deprecated in Drake release + */ + @Deprecated + public static Criterion matchUdpDst(short udpPort) { + return new UdpPortCriterion(TpPort.tpPort(udpPort), Type.UDP_DST); + } + + /** + * Creates a match on UDP destination port field using the specified value. + * + * @param udpPort UDP destination port + * @return match criterion + */ + public static Criterion matchUdpDst(TpPort udpPort) { + return new UdpPortCriterion(udpPort, Type.UDP_DST); + } + + /** + * Creates a match on SCTP source port field using the specified value. + * + * @param sctpPort SCTP source port + * @return match criterion + * @deprecated in Drake release + */ + @Deprecated + public static Criterion matchSctpSrc(short sctpPort) { + return new SctpPortCriterion(TpPort.tpPort(sctpPort), Type.SCTP_SRC); + } + + /** + * Creates a match on SCTP source port field using the specified value. + * + * @param sctpPort SCTP source port + * @return match criterion + */ + public static Criterion matchSctpSrc(TpPort sctpPort) { + return new SctpPortCriterion(sctpPort, Type.SCTP_SRC); + } + + /** + * Creates a match on SCTP destination port field using the specified + * value. + * + * @param sctpPort SCTP destination port + * @return match criterion + * @deprecated in Drake release + */ + @Deprecated + public static Criterion matchSctpDst(short sctpPort) { + return new SctpPortCriterion(TpPort.tpPort(sctpPort), Type.SCTP_DST); + } + + /** + * Creates a match on SCTP destination port field using the specified + * value. + * + * @param sctpPort SCTP destination port + * @return match criterion + */ + public static Criterion matchSctpDst(TpPort sctpPort) { + return new SctpPortCriterion(sctpPort, Type.SCTP_DST); + } + + /** + * Creates a match on ICMP type field using the specified value. + * + * @param icmpType ICMP type (8 bits unsigned integer) + * @return match criterion + */ + public static Criterion matchIcmpType(short icmpType) { + return new IcmpTypeCriterion(icmpType); + } + + /** + * Creates a match on ICMP code field using the specified value. + * + * @param icmpCode ICMP code (8 bits unsigned integer) + * @return match criterion + */ + public static Criterion matchIcmpCode(short icmpCode) { + return new IcmpCodeCriterion(icmpCode); + } + + /** + * Creates a match on IPv6 source field using the specified value. + * + * @param ip ipv6 source value + * @return match criterion + */ + public static Criterion matchIPv6Src(IpPrefix ip) { + return new IPCriterion(ip, Type.IPV6_SRC); + } + + /** + * Creates a match on IPv6 destination field using the specified value. + * + * @param ip ipv6 destination value + * @return match criterion + */ + public static Criterion matchIPv6Dst(IpPrefix ip) { + return new IPCriterion(ip, Type.IPV6_DST); + } + + /** + * Creates a match on IPv6 flow label field using the specified value. + * + * @param flowLabel IPv6 flow label (20 bits) + * @return match criterion + */ + public static Criterion matchIPv6FlowLabel(int flowLabel) { + return new IPv6FlowLabelCriterion(flowLabel); + } + + /** + * Creates a match on ICMPv6 type field using the specified value. + * + * @param icmpv6Type ICMPv6 type (8 bits unsigned integer) + * @return match criterion + */ + public static Criterion matchIcmpv6Type(short icmpv6Type) { + return new Icmpv6TypeCriterion(icmpv6Type); + } + + /** + * Creates a match on ICMPv6 code field using the specified value. + * + * @param icmpv6Code ICMPv6 code (8 bits unsigned integer) + * @return match criterion + */ + public static Criterion matchIcmpv6Code(short icmpv6Code) { + return new Icmpv6CodeCriterion(icmpv6Code); + } + + /** + * Creates a match on IPv6 Neighbor Discovery target address using the + * specified value. + * + * @param targetAddress IPv6 Neighbor Discovery target address + * @return match criterion + */ + public static Criterion matchIPv6NDTargetAddress(Ip6Address targetAddress) { + return new IPv6NDTargetAddressCriterion(targetAddress); + } + + /** + * Creates a match on IPv6 Neighbor Discovery source link-layer address + * using the specified value. + * + * @param mac IPv6 Neighbor Discovery source link-layer address + * @return match criterion + */ + public static Criterion matchIPv6NDSourceLinkLayerAddress(MacAddress mac) { + return new IPv6NDLinkLayerAddressCriterion(mac, Type.IPV6_ND_SLL); + } + + /** + * Creates a match on IPv6 Neighbor Discovery target link-layer address + * using the specified value. + * + * @param mac IPv6 Neighbor Discovery target link-layer address + * @return match criterion + */ + public static Criterion matchIPv6NDTargetLinkLayerAddress(MacAddress mac) { + return new IPv6NDLinkLayerAddressCriterion(mac, Type.IPV6_ND_TLL); + } + + /** + * Creates a match on MPLS label. + * + * @param mplsLabel MPLS label (20 bits) + * @return match criterion + */ + public static Criterion matchMplsLabel(MplsLabel mplsLabel) { + return new MplsCriterion(mplsLabel); + } + + /** + * Creates a match on MPLS Bottom-of-Stack indicator bit. + * + * @param mplsBos boolean value indicating true (BOS=1) or false (BOS=0) + * @return match criterion + */ + public static Criterion matchMplsLabel(boolean mplsBos) { + return new MplsBosCriterion(mplsBos); + } + + /** + * Creates a match on Tunnel ID. + * + * @param tunnelId Tunnel ID (64 bits) + * @return match criterion + */ + public static Criterion matchTunnelId(long tunnelId) { + return new TunnelIdCriterion(tunnelId); + } + + /** + * Creates a match on IPv6 Extension Header pseudo-field fiags. + * Those are defined in Criterion.IPv6ExthdrFlags. + * + * @param exthdrFlags IPv6 Extension Header pseudo-field flags (16 bits) + * @return match criterion + */ + public static Criterion matchIPv6ExthdrFlags(int exthdrFlags) { + 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. + * + * @param lambda lambda + * @return match criterion + */ + public static Criterion matchLambda(Lambda lambda) { + if (lambda instanceof IndexedLambda) { + return new IndexedLambdaCriterion((IndexedLambda) lambda); + } else if (lambda instanceof OchSignal) { + return new OchSignalCriterion((OchSignal) lambda); + } else { + throw new UnsupportedOperationException(String.format("Unsupported type of Lambda: %s", lambda)); + } + } + + /** + * 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. + * + * @param signalType OCh signal type + * @return match criterion + */ + public static Criterion matchOchSignalType(OchSignalType signalType) { + return new OchSignalTypeCriterion(signalType); + } + + public static Criterion dummy() { + return new DummyCriterion(); + } + + /** + * Dummy Criterion used with @see{FilteringObjective}. + */ + private static class DummyCriterion implements Criterion { + + @Override + public Type type() { + return Type.DUMMY; + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criterion.java new file mode 100644 index 00000000..12ab57de --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Criterion.java @@ -0,0 +1,181 @@ +/* + * Copyright 2014-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.criteria; + + +/** + * Representation of a single header field selection. + */ +public interface Criterion { + + /** + * Types of fields to which the selection criterion may apply. + */ + // From page 75 of OpenFlow 1.5.0 spec + enum Type { + /** Switch input port. */ + IN_PORT, + /** Switch physical input port. */ + IN_PHY_PORT, + /** Metadata passed between tables. */ + METADATA, + /** Ethernet destination address. */ + ETH_DST, + /** Ethernet source address. */ + ETH_SRC, + /** Ethernet frame type. */ + ETH_TYPE, + /** VLAN id. */ + VLAN_VID, + /** VLAN priority. */ + VLAN_PCP, + /** IP DSCP (6 bits in ToS field). */ + IP_DSCP, + /** IP ECN (2 bits in ToS field). */ + IP_ECN, + /** IP protocol. */ + IP_PROTO, + /** IPv4 source address. */ + IPV4_SRC, + /** IPv4 destination address. */ + IPV4_DST, + /** TCP source port. */ + TCP_SRC, + /** TCP destination port. */ + TCP_DST, + /** UDP source port. */ + UDP_SRC, + /** UDP destination port. */ + UDP_DST, + /** SCTP source port. */ + SCTP_SRC, + /** SCTP destination port. */ + SCTP_DST, + /** ICMP type. */ + ICMPV4_TYPE, + /** ICMP code. */ + ICMPV4_CODE, + /** ARP opcode. */ + ARP_OP, + /** ARP source IPv4 address. */ + ARP_SPA, + /** ARP target IPv4 address. */ + ARP_TPA, + /** ARP source hardware address. */ + ARP_SHA, + /** ARP target hardware address. */ + ARP_THA, + /** IPv6 source address. */ + IPV6_SRC, + /** IPv6 destination address. */ + IPV6_DST, + /** IPv6 Flow Label. */ + IPV6_FLABEL, + /** ICMPv6 type. */ + ICMPV6_TYPE, + /** ICMPv6 code. */ + ICMPV6_CODE, + /** Target address for ND. */ + IPV6_ND_TARGET, + /** Source link-layer for ND. */ + IPV6_ND_SLL, + /** Target link-layer for ND. */ + IPV6_ND_TLL, + /** MPLS label. */ + MPLS_LABEL, + /** MPLS TC. */ + MPLS_TC, + /** MPLS BoS bit. */ + MPLS_BOS, + /** PBB I-SID. */ + PBB_ISID, + /** Logical Port Metadata. */ + TUNNEL_ID, + /** IPv6 Extension Header pseudo-field. */ + IPV6_EXTHDR, + /** Unassigned value: 40. */ + UNASSIGNED_40, + /** PBB UCA header field. */ + PBB_UCA, + /** TCP flags. */ + TCP_FLAGS, + /** Output port from action set metadata. */ + ACTSET_OUTPUT, + /** Packet type value. */ + PACKET_TYPE, + + // + // NOTE: Everything below is defined elsewhere: ONOS-specific, + // extensions, etc. + // + /** Optical channel signal ID (lambda). */ + OCH_SIGID, + /** Optical channel signal type (fixed or flexible). */ + OCH_SIGTYPE, + + /** + * An empty criterion. + */ + DUMMY + } + + /** + * Returns the type of criterion. + * + * @return type of criterion + */ + Type type(); + + /** + * Bit definitions for IPv6 Extension Header pseudo-field. + * From page 79 of OpenFlow 1.5.0 spec. + */ + enum IPv6ExthdrFlags { + /** "No next header" encountered. */ + NONEXT((short) (1 << 0)), + /** Encrypted Sec Payload header present. */ + ESP((short) (1 << 1)), + /** Authentication header present. */ + AUTH((short) (1 << 2)), + /** 1 or 2 dest headers present. */ + DEST((short) (1 << 3)), + /** Fragment header present. */ + FRAG((short) (1 << 4)), + /** Router header present. */ + ROUTER((short) (1 << 5)), + /** Hop-by-hop header present. */ + HOP((short) (1 << 6)), + /** Unexpected repeats encountered. */ + UNREP((short) (1 << 7)), + /** Unexpected sequencing encountered. */ + UNSEQ((short) (1 << 8)); + + private short value; + + IPv6ExthdrFlags(short value) { + this.value = value; + } + + /** + * Gets the value as an integer. + * + * @return the value as an integer + */ + public short getValue() { + return this.value; + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/EthCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/EthCriterion.java new file mode 100644 index 00000000..6020974d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/EthCriterion.java @@ -0,0 +1,80 @@ +/* + * 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.criteria; + +import org.onlab.packet.MacAddress; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of MAC address criterion. + */ +public final class EthCriterion implements Criterion { + private final MacAddress mac; + private final Type type; + + /** + * Constructor. + * + * @param mac the source or destination MAC address to match + * @param type the match type. Should be either Type.ETH_DST or + * Type.ETH_SRC + */ + EthCriterion(MacAddress mac, Type type) { + this.mac = mac; + this.type = type; + } + + @Override + public Type type() { + return this.type; + } + + /** + * Gets the MAC address to match. + * + * @return the MAC address to match + */ + public MacAddress mac() { + return this.mac; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("mac", mac).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type.ordinal(), mac); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof EthCriterion) { + EthCriterion that = (EthCriterion) obj; + return Objects.equals(mac, that.mac) && + Objects.equals(type, that.type); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/EthTypeCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/EthTypeCriterion.java new file mode 100644 index 00000000..b2666d4d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/EthTypeCriterion.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.criteria; + +import org.onlab.packet.EthType; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of Ethernet type criterion (16 bits unsigned integer). + */ +public final class EthTypeCriterion implements Criterion { + + + private final EthType ethType; + + /** + * Constructor. + * + * @param ethType the Ethernet frame type to match (16 bits unsigned + * integer) + */ + EthTypeCriterion(int ethType) { + this.ethType = new EthType(ethType); + } + + /** + * Constructor. + * + * @param ethType the Ethernet frame type to match + */ + EthTypeCriterion(EthType ethType) { + this.ethType = ethType; + } + + @Override + public Type type() { + return Type.ETH_TYPE; + } + + /** + * Gets the Ethernet frame type to match. + * + * @return the Ethernet frame type to match (16 bits unsigned integer) + */ + public EthType ethType() { + return ethType; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("ethType", ethType.toString()) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), ethType); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof EthTypeCriterion) { + EthTypeCriterion that = (EthTypeCriterion) obj; + return Objects.equals(ethType, that.ethType) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPCriterion.java new file mode 100644 index 00000000..018afe80 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPCriterion.java @@ -0,0 +1,80 @@ +/* + * 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.criteria; + +import org.onlab.packet.IpPrefix; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of IP address criterion. + */ +public final class IPCriterion implements Criterion { + private final IpPrefix ip; + private final Type type; + + /** + * Constructor. + * + * @param ip the IP prefix to match. Could be either IPv4 or IPv6 + * @param type the match type. Should be one of the following: + * Type.IPV4_SRC, Type.IPV4_DST, Type.IPV6_SRC, Type.IPV6_DST + */ + IPCriterion(IpPrefix ip, Type type) { + this.ip = ip; + this.type = type; + } + + @Override + public Type type() { + return this.type; + } + + /** + * Gets the IP prefix to match. + * + * @return the IP prefix to match + */ + public IpPrefix ip() { + return this.ip; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("ip", ip).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), ip); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof IPCriterion) { + IPCriterion that = (IPCriterion) obj; + return Objects.equals(ip, that.ip) && + Objects.equals(type, that.type); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPDscpCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPDscpCriterion.java new file mode 100644 index 00000000..8634aa66 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPDscpCriterion.java @@ -0,0 +1,76 @@ +/* + * 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.criteria; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of IP DSCP (Differentiated Services Code Point) + * criterion (6 bits). + */ +public final class IPDscpCriterion implements Criterion { + private static final byte MASK = 0x3f; + private final byte ipDscp; // IP DSCP value: 6 bits + + /** + * Constructor. + * + * @param ipDscp the IP DSCP value to match + */ + IPDscpCriterion(byte ipDscp) { + this.ipDscp = (byte) (ipDscp & MASK); + } + + @Override + public Type type() { + return Type.IP_DSCP; + } + + /** + * Gets the IP DSCP value to match. + * + * @return the IP DSCP value to match + */ + public byte ipDscp() { + return ipDscp; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("ipDscp", Long.toHexString(ipDscp)).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), ipDscp); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof IPDscpCriterion) { + IPDscpCriterion that = (IPDscpCriterion) obj; + return Objects.equals(ipDscp, that.ipDscp) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPEcnCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPEcnCriterion.java new file mode 100644 index 00000000..48b3fbf6 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPEcnCriterion.java @@ -0,0 +1,76 @@ +/* + * 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.criteria; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of IP ECN (Explicit Congestion Notification) criterion + * (2 bits). + */ +public final class IPEcnCriterion implements Criterion { + private static final byte MASK = 0x3; + private final byte ipEcn; // IP ECN value: 2 bits + + /** + * Constructor. + * + * @param ipEcn the IP ECN value to match (2 bits) + */ + IPEcnCriterion(byte ipEcn) { + this.ipEcn = (byte) (ipEcn & MASK); + } + + @Override + public Type type() { + return Type.IP_ECN; + } + + /** + * Gets the IP ECN value to match. + * + * @return the IP ECN value to match (2 bits) + */ + public byte ipEcn() { + return ipEcn; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("ipEcn", Long.toHexString(ipEcn)).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), ipEcn); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof IPEcnCriterion) { + IPEcnCriterion that = (IPEcnCriterion) obj; + return Objects.equals(ipEcn, that.ipEcn) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPProtocolCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPProtocolCriterion.java new file mode 100644 index 00000000..6879f802 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPProtocolCriterion.java @@ -0,0 +1,76 @@ +/* + * 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.criteria; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of Internet Protocol Number criterion (8 bits unsigned) + * integer. + */ +public final class IPProtocolCriterion implements Criterion { + private static final short MASK = 0xff; + private final short proto; // IP protocol number: 8 bits + + /** + * Constructor. + * + * @param protocol the IP protocol (e.g., TCP=6, UDP=17) to match + * (8 bits unsigned integer) + */ + IPProtocolCriterion(short protocol) { + this.proto = (short) (protocol & MASK); + } + + @Override + public Type type() { + return Type.IP_PROTO; + } + + /** + * Gets the IP protocol to match. + * + * @return the IP protocol to match (8 bits unsigned integer) + */ + public short protocol() { + return proto; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("protocol", proto).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), proto); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof IPProtocolCriterion) { + IPProtocolCriterion that = (IPProtocolCriterion) obj; + return Objects.equals(proto, that.proto); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6ExthdrFlagsCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6ExthdrFlagsCriterion.java new file mode 100644 index 00000000..2463bf64 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6ExthdrFlagsCriterion.java @@ -0,0 +1,78 @@ +/* + * 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.criteria; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of IPv6 Extension Header pseudo-field criterion + * (16 bits). Those are defined in Criterion.IPv6ExthdrFlags. + */ +public final class IPv6ExthdrFlagsCriterion implements Criterion { + private static final int MASK = 0xffff; + private final int exthdrFlags; // IPv6 Exthdr flags: 16 bits + + /** + * Constructor. + * + * @param exthdrFlags the IPv6 Extension Header pseudo-field flags + * to match (16 bits). Those are defined in Criterion.IPv6ExthdrFlags + */ + IPv6ExthdrFlagsCriterion(int exthdrFlags) { + this.exthdrFlags = exthdrFlags & MASK; + } + + @Override + public Type type() { + return Type.IPV6_EXTHDR; + } + + /** + * Gets the IPv6 Extension Header pseudo-field flags to match. + * + * @return the IPv6 Extension Header pseudo-field flags to match + * (16 bits). Those are defined in Criterion.IPv6ExthdrFlags + */ + public int exthdrFlags() { + return exthdrFlags; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("exthdrFlags", Long.toHexString(exthdrFlags)).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), exthdrFlags); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof IPv6ExthdrFlagsCriterion) { + IPv6ExthdrFlagsCriterion that = (IPv6ExthdrFlagsCriterion) obj; + return Objects.equals(exthdrFlags, that.exthdrFlags) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6FlowLabelCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6FlowLabelCriterion.java new file mode 100644 index 00000000..6e1021d9 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6FlowLabelCriterion.java @@ -0,0 +1,76 @@ +/* + * 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.criteria; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of IPv6 Flow Label (RFC 6437) criterion (20 bits unsigned + * integer). + */ +public final class IPv6FlowLabelCriterion implements Criterion { + private static final int MASK = 0xfffff; + private final int flowLabel; // IPv6 flow label: 20 bits + + /** + * Constructor. + * + * @param flowLabel the IPv6 flow label to match (20 bits) + */ + IPv6FlowLabelCriterion(int flowLabel) { + this.flowLabel = flowLabel & MASK; + } + + @Override + public Type type() { + return Type.IPV6_FLABEL; + } + + /** + * Gets the IPv6 flow label to match. + * + * @return the IPv6 flow label to match (20 bits) + */ + public int flowLabel() { + return flowLabel; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("flowLabel", Long.toHexString(flowLabel)).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), flowLabel); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof IPv6FlowLabelCriterion) { + IPv6FlowLabelCriterion that = (IPv6FlowLabelCriterion) obj; + return Objects.equals(flowLabel, that.flowLabel) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6NDLinkLayerAddressCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6NDLinkLayerAddressCriterion.java new file mode 100644 index 00000000..9f310d4a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6NDLinkLayerAddressCriterion.java @@ -0,0 +1,81 @@ +/* + * 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.criteria; + +import org.onlab.packet.MacAddress; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of IPv6 Neighbor Discovery link-layer address criterion. + */ +public final class IPv6NDLinkLayerAddressCriterion implements Criterion { + private final MacAddress mac; + private final Type type; + + /** + * Constructor. + * + * @param mac the source or destination link-layer address to match + * @param type the match type. Should be either Type.IPV6_ND_SLL or + * Type.IPV6_ND_TLL + */ + IPv6NDLinkLayerAddressCriterion(MacAddress mac, Type type) { + this.mac = mac; + this.type = type; + } + + @Override + public Type type() { + return this.type; + } + + /** + * Gets the MAC link-layer address to match. + * + * @return the MAC link-layer address to match + */ + public MacAddress mac() { + return this.mac; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("mac", mac).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), mac); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof IPv6NDLinkLayerAddressCriterion) { + IPv6NDLinkLayerAddressCriterion that = + (IPv6NDLinkLayerAddressCriterion) obj; + return Objects.equals(mac, that.mac) && + Objects.equals(type, that.type); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6NDTargetAddressCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6NDTargetAddressCriterion.java new file mode 100644 index 00000000..ffef044a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IPv6NDTargetAddressCriterion.java @@ -0,0 +1,77 @@ +/* + * 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.criteria; + +import org.onlab.packet.Ip6Address; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of IPv6 Neighbor Discovery target address criterion. + */ +public final class IPv6NDTargetAddressCriterion implements Criterion { + private final Ip6Address targetAddress; + + /** + * Constructor. + * + * @param targetAddress the IPv6 target address to match + */ + IPv6NDTargetAddressCriterion(Ip6Address targetAddress) { + this.targetAddress = targetAddress; + } + + @Override + public Type type() { + return Type.IPV6_ND_TARGET; + } + + /** + * Gets the IPv6 target address to match. + * + * @return the IPv6 target address to match + */ + public Ip6Address targetAddress() { + return this.targetAddress; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("targetAddress", targetAddress).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), targetAddress); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof IPv6NDTargetAddressCriterion) { + IPv6NDTargetAddressCriterion that = + (IPv6NDTargetAddressCriterion) obj; + return Objects.equals(targetAddress, that.targetAddress) && + Objects.equals(type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IcmpCodeCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IcmpCodeCriterion.java new file mode 100644 index 00000000..516f61b3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IcmpCodeCriterion.java @@ -0,0 +1,75 @@ +/* + * 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.criteria; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of ICMP code criterion (8 bits unsigned integer). + */ +public final class IcmpCodeCriterion implements Criterion { + private static final short MASK = 0xff; + private final short icmpCode; // The ICMP code: 8 bits + + /** + * Constructor. + * + * @param icmpCode the ICMP code to match (8 bits unsigned integer) + */ + IcmpCodeCriterion(short icmpCode) { + this.icmpCode = (short) (icmpCode & MASK); + } + + @Override + public Type type() { + return Type.ICMPV4_CODE; + } + + /** + * Gets the ICMP code to match. + * + * @return the ICMP code to match (8 bits unsigned integer) + */ + public short icmpCode() { + return icmpCode; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("icmpCode", icmpCode).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), icmpCode); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof IcmpCodeCriterion) { + IcmpCodeCriterion that = (IcmpCodeCriterion) obj; + return Objects.equals(icmpCode, that.icmpCode) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IcmpTypeCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IcmpTypeCriterion.java new file mode 100644 index 00000000..63251425 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IcmpTypeCriterion.java @@ -0,0 +1,75 @@ +/* + * 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.criteria; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of ICMP type criterion (8 bits unsigned integer). + */ +public final class IcmpTypeCriterion implements Criterion { + private static final short MASK = 0xff; + private final short icmpType; // The ICMP type: 8 bits + + /** + * Constructor. + * + * @param icmpType the ICMP type to match (8 bits unsigned integer) + */ + IcmpTypeCriterion(short icmpType) { + this.icmpType = (short) (icmpType & MASK); + } + + @Override + public Type type() { + return Type.ICMPV4_TYPE; + } + + /** + * Gets the ICMP type to match. + * + * @return the ICMP type to match (8 bits unsigned integer) + */ + public short icmpType() { + return icmpType; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("icmpType", icmpType).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), icmpType); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof IcmpTypeCriterion) { + IcmpTypeCriterion that = (IcmpTypeCriterion) obj; + return Objects.equals(icmpType, that.icmpType) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Icmpv6CodeCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Icmpv6CodeCriterion.java new file mode 100644 index 00000000..a41b6fef --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Icmpv6CodeCriterion.java @@ -0,0 +1,75 @@ +/* + * 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.criteria; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of ICMPv6 code criterion (8 bits unsigned integer). + */ +public final class Icmpv6CodeCriterion implements Criterion { + private static final short MASK = 0xff; + private final short icmpv6Code; // ICMPv6 code: 8 bits + + /** + * Constructor. + * + * @param icmpv6Code the ICMPv6 code to match (8 bits unsigned integer) + */ + Icmpv6CodeCriterion(short icmpv6Code) { + this.icmpv6Code = (short) (icmpv6Code & MASK); + } + + @Override + public Type type() { + return Type.ICMPV6_CODE; + } + + /** + * Gets the ICMPv6 code to match. + * + * @return the ICMPv6 code to match (8 bits unsigned integer) + */ + public short icmpv6Code() { + return icmpv6Code; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("icmpv6Code", icmpv6Code).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), icmpv6Code); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Icmpv6CodeCriterion) { + Icmpv6CodeCriterion that = (Icmpv6CodeCriterion) obj; + return Objects.equals(icmpv6Code, that.icmpv6Code) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Icmpv6TypeCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Icmpv6TypeCriterion.java new file mode 100644 index 00000000..7410ba17 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/Icmpv6TypeCriterion.java @@ -0,0 +1,75 @@ +/* + * 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.criteria; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of ICMPv6 type criterion (8 bits unsigned integer). + */ +public final class Icmpv6TypeCriterion implements Criterion { + private static final short MASK = 0xff; + private final short icmpv6Type; // ICMPv6 type: 8 bits + + /** + * Constructor. + * + * @param icmpv6Type the ICMPv6 type to match (8 bits unsigned integer) + */ + Icmpv6TypeCriterion(short icmpv6Type) { + this.icmpv6Type = (short) (icmpv6Type & MASK); + } + + @Override + public Type type() { + return Type.ICMPV6_TYPE; + } + + /** + * Gets the ICMPv6 type to match. + * + * @return the ICMPv6 type to match (8 bits unsigned integer) + */ + public short icmpv6Type() { + return icmpv6Type; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("icmpv6Type", icmpv6Type).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), icmpv6Type); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Icmpv6TypeCriterion) { + Icmpv6TypeCriterion that = (Icmpv6TypeCriterion) obj; + return Objects.equals(icmpv6Type, that.icmpv6Type) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IndexedLambdaCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IndexedLambdaCriterion.java new file mode 100644 index 00000000..88a6fe10 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/IndexedLambdaCriterion.java @@ -0,0 +1,80 @@ +/* + * 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.criteria; + +import com.google.common.base.MoreObjects; +import org.onosproject.net.IndexedLambda; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Implementation of indexed lambda criterion. + */ +public class IndexedLambdaCriterion implements Criterion { + + private final IndexedLambda lambda; + + /** + * Creates a criterion with the specified value. + * + * @param lambda lambda index number + */ + IndexedLambdaCriterion(IndexedLambda lambda) { + this.lambda = checkNotNull(lambda); + } + + @Override + public Type type() { + // TODO: consider defining a new specific type + // Now OCH_SIGID is used due to compatibility concerns + return Type.OCH_SIGID; + } + + /** + * Returns the indexed lambda to match. + * + * @return the indexed lambda to match + */ + public IndexedLambda lambda() { + return lambda; + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), lambda); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof IndexedLambdaCriterion)) { + return false; + } + final IndexedLambdaCriterion that = (IndexedLambdaCriterion) obj; + return Objects.equals(this.lambda, that.lambda); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("lambda", lambda) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/LambdaCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/LambdaCriterion.java new file mode 100644 index 00000000..656800b1 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/LambdaCriterion.java @@ -0,0 +1,80 @@ +/* + * 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.criteria; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of lambda (wavelength) criterion (16 bits unsigned + * integer). + */ +public final class LambdaCriterion implements Criterion { + private static final int MASK = 0xffff; + private final int lambda; // Lambda value: 16 bits + private final Type type; + + /** + * Constructor. + * + * @param lambda the lambda (wavelength) to match (16 bits unsigned + * integer) + * @param type the match type. Should be Type.OCH_SIGID + */ + LambdaCriterion(int lambda, Type type) { + this.lambda = lambda & MASK; + this.type = type; + } + + @Override + public Type type() { + return this.type; + } + + /** + * Gets the lambda (wavelength) to match. + * + * @return the lambda (wavelength) to match (16 bits unsigned integer) + */ + public int lambda() { + return lambda; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("lambda", lambda).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), lambda); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof LambdaCriterion) { + LambdaCriterion that = (LambdaCriterion) obj; + return Objects.equals(lambda, that.lambda) && + Objects.equals(type, that.type); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/MetadataCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/MetadataCriterion.java new file mode 100644 index 00000000..8177b483 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/MetadataCriterion.java @@ -0,0 +1,75 @@ +/* + * 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.criteria; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of Metadata criterion. + */ +public final class MetadataCriterion implements Criterion { + private final long metadata; + + /** + * Constructor. + * + * @param metadata the metadata to match (64 bits data) + */ + MetadataCriterion(long metadata) { + this.metadata = metadata; + } + + @Override + public Type type() { + return Type.METADATA; + } + + /** + * Gets the metadata to match. + * + * @return the metadata to match (64 bits data) + */ + public long metadata() { + return metadata; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("metadata", Long.toHexString(metadata)) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), metadata); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof MetadataCriterion) { + MetadataCriterion that = (MetadataCriterion) obj; + return Objects.equals(metadata, that.metadata) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/MplsBosCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/MplsBosCriterion.java new file mode 100644 index 00000000..1ace8931 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/MplsBosCriterion.java @@ -0,0 +1,48 @@ +package org.onosproject.net.flow.criteria; + +import static com.google.common.base.MoreObjects.toStringHelper; +import java.util.Objects; + +/** + * Implementation of MPLS BOS criterion (1 bit). + */ +public class MplsBosCriterion implements Criterion { + private boolean mplsBos; + + MplsBosCriterion(boolean mplsBos) { + this.mplsBos = mplsBos; + } + + @Override + public Type type() { + return Type.MPLS_BOS; + } + + public boolean mplsBos() { + return mplsBos; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("bos", mplsBos).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), mplsBos); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof MplsBosCriterion) { + MplsBosCriterion that = (MplsBosCriterion) obj; + return Objects.equals(mplsBos, that.mplsBos()) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/MplsCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/MplsCriterion.java new file mode 100644 index 00000000..34d384f1 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/MplsCriterion.java @@ -0,0 +1,67 @@ +/* + * 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.criteria; + +import org.onlab.packet.MplsLabel; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of MPLS tag criterion (20 bits). + */ +public final class MplsCriterion implements Criterion { + private static final int MASK = 0xfffff; + private final MplsLabel mplsLabel; + + MplsCriterion(MplsLabel mplsLabel) { + this.mplsLabel = mplsLabel; + } + + @Override + public Type type() { + return Type.MPLS_LABEL; + } + + public MplsLabel label() { + return mplsLabel; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("mpls", mplsLabel).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), mplsLabel); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof MplsCriterion) { + MplsCriterion that = (MplsCriterion) obj; + return Objects.equals(mplsLabel, that.mplsLabel) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OchSignalCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OchSignalCriterion.java new file mode 100644 index 00000000..3a51a6bd --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OchSignalCriterion.java @@ -0,0 +1,81 @@ +/* + * 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.criteria; + +import com.google.common.base.MoreObjects; +import org.onosproject.net.OchSignal; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Implementation of OCh (Optical Channel) signal criterion. + * This criterion is based on the specification of "OFPXMT_EXP_OCH_SIGID" in + * Open Networking Foundation "Optical Transport Protocol Extension Version 1.0", but + * defined in protocol agnostic way. + */ +public final class OchSignalCriterion implements Criterion { + + private final OchSignal lambda; + + /** + * Create an instance with the specified OCh signal. + * + * @param lambda OCh signal + */ + OchSignalCriterion(OchSignal lambda) { + this.lambda = checkNotNull(lambda); + } + + @Override + public Type type() { + return Type.OCH_SIGID; + } + + /** + * Returns the OCh signal to match. + * + * @return the OCh signal to match + */ + public OchSignal lambda() { + return lambda; + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), lambda); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof OchSignalCriterion)) { + return false; + } + final OchSignalCriterion that = (OchSignalCriterion) obj; + return Objects.equals(this.lambda, that.lambda); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("lambda", lambda) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OchSignalTypeCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OchSignalTypeCriterion.java new file mode 100644 index 00000000..cf838bf3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OchSignalTypeCriterion.java @@ -0,0 +1,78 @@ +/* + * 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.criteria; + +import com.google.common.base.MoreObjects; +import org.onosproject.net.OchSignalType; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Implementation of OCh (Optical Channel) signal type criterion. + */ +public class OchSignalTypeCriterion implements Criterion { + + private final OchSignalType signalType; + + /** + * Creates a criterion with the specified value. + * + * @param signalType OCh signal type + */ + OchSignalTypeCriterion(OchSignalType signalType) { + this.signalType = checkNotNull(signalType); + } + + @Override + public Type type() { + return Type.OCH_SIGTYPE; + } + + /** + * Returns the OCh signal type to match. + * + * @return the OCh signal type to match + */ + public OchSignalType signalType() { + return signalType; + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), signalType); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof OchSignalTypeCriterion)) { + return false; + } + final OchSignalTypeCriterion that = (OchSignalTypeCriterion) obj; + return Objects.equals(this.signalType, that.signalType); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("signalType", signalType) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OpticalSignalTypeCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OpticalSignalTypeCriterion.java new file mode 100644 index 00000000..b712675b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/OpticalSignalTypeCriterion.java @@ -0,0 +1,83 @@ +/* + * 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.criteria; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of optical signal type criterion (8 bits unsigned + * integer). + * + * @deprecated in Cardinal Release + */ +@Deprecated +public final class OpticalSignalTypeCriterion implements Criterion { + private static final short MASK = 0xff; + private final short signalType; // Signal type value: 8 bits + private final Type type; + + /** + * Constructor. + * + * @param signalType the optical signal type to match (8 bits unsigned + * integer) + * @param type the match type. Should be Type.OCH_SIGTYPE + */ + OpticalSignalTypeCriterion(short signalType, Type type) { + this.signalType = (short) (signalType & MASK); + this.type = type; + } + + @Override + public Type type() { + return this.type; + } + + /** + * Gets the optical signal type to match. + * + * @return the optical signal type to match (8 bits unsigned integer) + */ + public short signalType() { + return signalType; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("signalType", signalType).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), signalType); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof OpticalSignalTypeCriterion) { + OpticalSignalTypeCriterion that = (OpticalSignalTypeCriterion) obj; + return Objects.equals(signalType, that.signalType) && + Objects.equals(type, that.type); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/PortCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/PortCriterion.java new file mode 100644 index 00000000..f07cd500 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/PortCriterion.java @@ -0,0 +1,80 @@ +/* + * 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.criteria; + +import org.onosproject.net.PortNumber; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of input port criterion. + */ +public final class PortCriterion implements Criterion { + private final PortNumber port; + private final Type type; + + /** + * Constructor. + * + * @param port the input port number to match + * @param type the match type. Should be either Type.IN_PORT or + * Type.IN_PHY_PORT + */ + PortCriterion(PortNumber port, Type type) { + this.port = port; + this.type = type; + } + + @Override + public Type type() { + return this.type; + } + + /** + * Gets the input port number to match. + * + * @return the input port number to match + */ + public PortNumber port() { + return this.port; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("port", port).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), port); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof PortCriterion) { + PortCriterion that = (PortCriterion) obj; + return Objects.equals(port, that.port) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/SctpPortCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/SctpPortCriterion.java new file mode 100644 index 00000000..2d4cf15a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/SctpPortCriterion.java @@ -0,0 +1,80 @@ +/* + * 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.criteria; + +import org.onlab.packet.TpPort; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of SCTP port criterion (16 bits unsigned integer). + */ +public final class SctpPortCriterion implements Criterion { + private final TpPort sctpPort; + private final Type type; + + /** + * Constructor. + * + * @param sctpPort the SCTP port to match + * @param type the match type. Should be either Type.SCTP_SRC or + * Type.SCTP_DST + */ + SctpPortCriterion(TpPort sctpPort, Type type) { + this.sctpPort = sctpPort; + this.type = type; + } + + @Override + public Type type() { + return this.type; + } + + /** + * Gets the SCTP port to match. + * + * @return the SCTP port to match + */ + public TpPort sctpPort() { + return this.sctpPort; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("sctpPort", sctpPort).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), sctpPort); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof SctpPortCriterion) { + SctpPortCriterion that = (SctpPortCriterion) obj; + return Objects.equals(sctpPort, that.sctpPort) && + Objects.equals(type, that.type); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/TcpPortCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/TcpPortCriterion.java new file mode 100644 index 00000000..e682b238 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/TcpPortCriterion.java @@ -0,0 +1,80 @@ +/* + * 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.criteria; + +import org.onlab.packet.TpPort; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of TCP port criterion (16 bits unsigned integer). + */ +public final class TcpPortCriterion implements Criterion { + private final TpPort tcpPort; + private final Type type; + + /** + * Constructor. + * + * @param tcpPort the TCP port to match + * @param type the match type. Should be either Type.TCP_SRC or + * Type.TCP_DST + */ + TcpPortCriterion(TpPort tcpPort, Type type) { + this.tcpPort = tcpPort; + this.type = type; + } + + @Override + public Type type() { + return this.type; + } + + /** + * Gets the TCP port to match. + * + * @return the TCP port to match + */ + public TpPort tcpPort() { + return this.tcpPort; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("tcpPort", tcpPort).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), tcpPort); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof TcpPortCriterion) { + TcpPortCriterion that = (TcpPortCriterion) obj; + return Objects.equals(tcpPort, that.tcpPort) && + Objects.equals(type, that.type); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/TunnelIdCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/TunnelIdCriterion.java new file mode 100644 index 00000000..3362c73f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/TunnelIdCriterion.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.net.flow.criteria; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; +/** + * Implementation of Tunnel ID criterion. + */ +public class TunnelIdCriterion implements Criterion { + private final long tunnelId; + + /** + * Constructor. + * + * @param tunnelId a Tunnel ID to match(64 bits) + */ + TunnelIdCriterion(long tunnelId) { + this.tunnelId = tunnelId; + } + + @Override + public Type type() { + return Type.TUNNEL_ID; + } + + /** + * Gets the Tunnel ID to match. + * + * @return the Tunnel ID to match (64 bits) + */ + public long tunnelId() { + return tunnelId; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("tunnelId", Long.toHexString(tunnelId)) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), tunnelId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof TunnelIdCriterion) { + TunnelIdCriterion that = (TunnelIdCriterion) obj; + return Objects.equals(tunnelId, that.tunnelId) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/UdpPortCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/UdpPortCriterion.java new file mode 100644 index 00000000..8a29f471 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/UdpPortCriterion.java @@ -0,0 +1,80 @@ +/* + * 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.criteria; + +import org.onlab.packet.TpPort; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of UDP port criterion (16 bits unsigned integer). + */ +public final class UdpPortCriterion implements Criterion { + private final TpPort udpPort; + private final Type type; + + /** + * Constructor. + * + * @param udpPort the UDP port to match + * @param type the match type. Should be either Type.UDP_SRC or + * Type.UDP_DST + */ + UdpPortCriterion(TpPort udpPort, Type type) { + this.udpPort = udpPort; + this.type = type; + } + + @Override + public Type type() { + return this.type; + } + + /** + * Gets the UDP port to match. + * + * @return the UDP port to match + */ + public TpPort udpPort() { + return this.udpPort; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("udpPort", udpPort).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), udpPort); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof UdpPortCriterion) { + UdpPortCriterion that = (UdpPortCriterion) obj; + return Objects.equals(udpPort, that.udpPort) && + Objects.equals(type, that.type); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/VlanIdCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/VlanIdCriterion.java new file mode 100644 index 00000000..c73edb12 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/VlanIdCriterion.java @@ -0,0 +1,76 @@ +/* + * 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.criteria; + +import org.onlab.packet.VlanId; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of VLAN ID criterion. + */ +public final class VlanIdCriterion implements Criterion { + private final VlanId vlanId; + + /** + * Constructor. + * + * @param vlanId the VLAN ID to match + */ + VlanIdCriterion(VlanId vlanId) { + this.vlanId = vlanId; + } + + @Override + public Type type() { + return Type.VLAN_VID; + } + + /** + * Gets the VLAN ID to match. + * + * @return the VLAN ID to match + */ + public VlanId vlanId() { + return vlanId; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("vlanId", vlanId).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), vlanId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof VlanIdCriterion) { + VlanIdCriterion that = (VlanIdCriterion) obj; + return Objects.equals(vlanId, that.vlanId) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/VlanPcpCriterion.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/VlanPcpCriterion.java new file mode 100644 index 00000000..0c83e141 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/VlanPcpCriterion.java @@ -0,0 +1,75 @@ +/* + * 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.criteria; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of VLAN priority criterion (3 bits). + */ +public final class VlanPcpCriterion implements Criterion { + private static final byte MASK = 0x7; + private final byte vlanPcp; // VLAN pcp value: 3 bits + + /** + * Constructor. + * + * @param vlanPcp the VLAN priority to match (3 bits) + */ + VlanPcpCriterion(byte vlanPcp) { + this.vlanPcp = (byte) (vlanPcp & MASK); + } + + @Override + public Type type() { + return Type.VLAN_PCP; + } + + /** + * Gets the VLAN priority to match. + * + * @return the VLAN priority to match (3 bits) + */ + public byte priority() { + return vlanPcp; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("priority", Long.toHexString(vlanPcp)).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), vlanPcp); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof VlanPcpCriterion) { + VlanPcpCriterion that = (VlanPcpCriterion) obj; + return Objects.equals(vlanPcp, that.vlanPcp) && + Objects.equals(this.type(), that.type()); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/package-info.java new file mode 100644 index 00000000..1f091928 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/criteria/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Traffic selection criteria model. + */ +package org.onosproject.net.flow.criteria; 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 new file mode 100644 index 00000000..6f2cac6b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java @@ -0,0 +1,84 @@ +/* + * Copyright 2014-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.instructions; + +/** + * Abstraction of a single traffic treatment step. + */ +public interface Instruction { + + /** + * Represents the type of traffic treatment. + */ + enum Type { + /** + * Signifies that the traffic should be dropped. + */ + DROP, + + /** + * Signifies that the traffic should be output to a port. + */ + OUTPUT, + + /** + * Signifies that traffic should be sent out of a group. + */ + GROUP, + + /** + * Signifies that traffic should be metered according to a meter. + */ + METER, + + /** + * Signifies that the traffic should be modified in L0 way. + */ + L0MODIFICATION, + + /** + * Signifies that the traffic should be modified in L2 way. + */ + L2MODIFICATION, + + /** + * Signifies that the traffic should be passed to another table. + */ + TABLE, + + /** + * Signifies that the traffic should be modified in L3 way. + */ + L3MODIFICATION, + + /** + * Signifies that metadata be attached to traffic. + */ + METADATA, + + /** + * Signifies that the traffic should be modified in L4 way. + */ + L4MODIFICATION + } + + /** + * Returns the type of instruction. + * @return type of instruction + */ + Type type(); + +} 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 new file mode 100644 index 00000000..c5358a29 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java @@ -0,0 +1,742 @@ +/* + * Copyright 2014-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.instructions; + +import org.onlab.packet.EthType; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.TpPort; +import org.onlab.packet.VlanId; +import org.onosproject.core.GroupId; +import org.onosproject.net.IndexedLambda; +import org.onosproject.net.Lambda; +import org.onosproject.net.OchSignal; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.instructions.L0ModificationInstruction.L0SubType; +import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction; +import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModOchSignalInstruction; +import org.onosproject.net.flow.instructions.L3ModificationInstruction.L3SubType; +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction; +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction; +import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModTtlInstruction; +import org.onosproject.net.flow.instructions.L4ModificationInstruction.L4SubType; +import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction; +import org.onosproject.net.meter.MeterId; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Factory class for creating various traffic treatment instructions. + */ +public final class Instructions { + + + // Ban construction + private Instructions() {} + + /** + * Creates an output instruction using the specified port number. This can + * include logical ports such as CONTROLLER, FLOOD, etc. + * + * @param number port number + * @return output instruction + */ + public static OutputInstruction createOutput(final PortNumber number) { + checkNotNull(number, "PortNumber cannot be null"); + return new OutputInstruction(number); + } + + /** + * Creates a drop instruction. + * + * @return drop instruction + */ + public static DropInstruction createDrop() { + return new DropInstruction(); + } + + /** + * Creates a group instruction. + * + * @param groupId Group Id + * @return group instruction + */ + public static GroupInstruction createGroup(final GroupId groupId) { + checkNotNull(groupId, "GroupId cannot be null"); + return new GroupInstruction(groupId); + } + + public static MeterInstruction meterTraffic(final MeterId meterId) { + checkNotNull(meterId, "meter id cannot be null"); + 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. + * + * @param lambda OCh signal + * @return an L0 modification + */ + public static L0ModificationInstruction modL0Lambda(Lambda lambda) { + checkNotNull(lambda, "L0 OCh signal cannot be null"); + + if (lambda instanceof IndexedLambda) { + return new ModLambdaInstruction(L0SubType.LAMBDA, (short) ((IndexedLambda) lambda).index()); + } else if (lambda instanceof OchSignal) { + return new ModOchSignalInstruction((OchSignal) lambda); + } else { + throw new UnsupportedOperationException(String.format("Unsupported type: %s", lambda)); + } + } + + /** + * Creates a l2 src modification. + * + * @param addr the mac address to modify to + * @return a l2 modification + */ + public static L2ModificationInstruction modL2Src(MacAddress addr) { + checkNotNull(addr, "Src l2 address cannot be null"); + return new L2ModificationInstruction.ModEtherInstruction( + L2ModificationInstruction.L2SubType.ETH_SRC, addr); + } + + /** + * Creates a L2 dst modification. + * + * @param addr the mac address to modify to + * @return a L2 modification + */ + public static L2ModificationInstruction modL2Dst(MacAddress addr) { + checkNotNull(addr, "Dst l2 address cannot be null"); + return new L2ModificationInstruction.ModEtherInstruction( + L2ModificationInstruction.L2SubType.ETH_DST, addr); + } + + /** + * Creates a VLAN ID modification. + * + * @param vlanId the VLAN ID to modify to + * @return a L2 modification + */ + public static L2ModificationInstruction modVlanId(VlanId vlanId) { + checkNotNull(vlanId, "VLAN id cannot be null"); + return new L2ModificationInstruction.ModVlanIdInstruction(vlanId); + } + + /** + * Creates a VLAN PCP modification. + * + * @param vlanPcp the PCP to modify to + * @return a L2 modification + */ + public static L2ModificationInstruction modVlanPcp(Byte vlanPcp) { + checkNotNull(vlanPcp, "VLAN Pcp cannot be null"); + return new L2ModificationInstruction.ModVlanPcpInstruction(vlanPcp); + } + + /** + * Creates a MPLS label modification. + * + * @param mplsLabel MPLS label to set + * @return a L2 Modification + */ + public static L2ModificationInstruction modMplsLabel(MplsLabel mplsLabel) { + checkNotNull(mplsLabel, "MPLS label cannot be null"); + return new L2ModificationInstruction.ModMplsLabelInstruction(mplsLabel); + } + + /** + * Creates a MPLS BOS bit modification. + * + * @param mplsBos MPLS BOS bit to set (true) or unset (false) + * @return a L2 Modification + */ + public static L2ModificationInstruction modMplsBos(boolean mplsBos) { + return new L2ModificationInstruction.ModMplsBosInstruction(mplsBos); + } + + /** + * Creates a MPLS decrement TTL modification. + * + * @return a L2 Modification + */ + public static L2ModificationInstruction decMplsTtl() { + return new L2ModificationInstruction.ModMplsTtlInstruction(); + } + + /** + * Creates a L3 IPv4 src modification. + * + * @param addr the IPv4 address to modify to + * @return a L3 modification + */ + public static L3ModificationInstruction modL3Src(IpAddress addr) { + checkNotNull(addr, "Src l3 IPv4 address cannot be null"); + return new ModIPInstruction(L3SubType.IPV4_SRC, addr); + } + + /** + * Creates a L3 IPv4 dst modification. + * + * @param addr the IPv4 address to modify to + * @return a L3 modification + */ + public static L3ModificationInstruction modL3Dst(IpAddress addr) { + checkNotNull(addr, "Dst l3 IPv4 address cannot be null"); + return new ModIPInstruction(L3SubType.IPV4_DST, addr); + } + + /** + * Creates a L3 IPv6 src modification. + * + * @param addr the IPv6 address to modify to + * @return a L3 modification + */ + public static L3ModificationInstruction modL3IPv6Src(IpAddress addr) { + checkNotNull(addr, "Src l3 IPv6 address cannot be null"); + return new ModIPInstruction(L3SubType.IPV6_SRC, addr); + } + + /** + * Creates a L3 IPv6 dst modification. + * + * @param addr the IPv6 address to modify to + * @return a L3 modification + */ + public static L3ModificationInstruction modL3IPv6Dst(IpAddress addr) { + checkNotNull(addr, "Dst l3 IPv6 address cannot be null"); + return new ModIPInstruction(L3SubType.IPV6_DST, addr); + } + + /** + * Creates a L3 IPv6 Flow Label modification. + * + * @param flowLabel the IPv6 flow label to modify to (20 bits) + * @return a L3 modification + */ + public static L3ModificationInstruction modL3IPv6FlowLabel(int flowLabel) { + return new ModIPv6FlowLabelInstruction(flowLabel); + } + + /** + * Creates a L3 decrement TTL modification. + * + * @return a L3 modification + */ + public static L3ModificationInstruction decNwTtl() { + return new ModTtlInstruction(L3SubType.DEC_TTL); + } + + /** + * Creates a L3 copy TTL to outer header modification. + * + * @return a L3 modification + */ + public static L3ModificationInstruction copyTtlOut() { + return new ModTtlInstruction(L3SubType.TTL_OUT); + } + + /** + * Creates a L3 copy TTL to inner header modification. + * + * @return a L3 modification + */ + public static L3ModificationInstruction copyTtlIn() { + return new ModTtlInstruction(L3SubType.TTL_IN); + } + + /** + * Creates a push MPLS header instruction. + * + * @return a L2 modification. + */ + public static Instruction pushMpls() { + return new L2ModificationInstruction.PushHeaderInstructions( + L2ModificationInstruction.L2SubType.MPLS_PUSH, + EthType.EtherType.MPLS_UNICAST.ethType()); + } + + /** + * Creates a pop MPLS header instruction. + * + * @return a L2 modification. + */ + public static Instruction popMpls() { + return new L2ModificationInstruction.PushHeaderInstructions( + L2ModificationInstruction.L2SubType.MPLS_POP, + 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. + * + * @param etherType Ethernet type to set + * @return a L2 modification. + */ + public static Instruction popMpls(EthType etherType) { + checkNotNull(etherType, "Ethernet type cannot be null"); + return new L2ModificationInstruction.PushHeaderInstructions( + L2ModificationInstruction.L2SubType.MPLS_POP, etherType); + } + + /** + * Creates a pop VLAN header instruction. + * + * @return a L2 modification + */ + public static Instruction popVlan() { + return new L2ModificationInstruction.PopVlanInstruction( + L2ModificationInstruction.L2SubType.VLAN_POP); + } + + /** + * Creates a push VLAN header instruction. + * + * @return a L2 modification + */ + public static Instruction pushVlan() { + return new L2ModificationInstruction.PushHeaderInstructions( + L2ModificationInstruction.L2SubType.VLAN_PUSH, + EthType.EtherType.VLAN.ethType()); + } + + /** + * Sends the packet to the table id. + * + * @param tableId flow rule table id + * @return table type transition instruction + */ + public static Instruction transition(Integer tableId) { + checkNotNull(tableId, "Table id cannot be null"); + return new TableTypeTransition(tableId); + } + + /** + * Writes metadata to associate with a packet. + * + * @param metadata the metadata value to write + * @param metadataMask the bits to mask for the metadata value + * @return metadata instruction + */ + public static Instruction writeMetadata(long metadata, long metadataMask) { + return new MetadataInstruction(metadata, metadataMask); + } + + /** + * Creates a Tunnel ID modification. + * + * @param tunnelId the Tunnel ID to modify to + * @return a L2 modification + */ + public static L2ModificationInstruction modTunnelId(long tunnelId) { + checkNotNull(tunnelId, "Tunnel id cannot be null"); + return new L2ModificationInstruction.ModTunnelIdInstruction(tunnelId); + } + + /** + * Creates a TCP src modification. + * + * @param port the TCP port number to modify to + * @return a L4 modification + * @deprecated in Drake release + */ + @Deprecated + public static L4ModificationInstruction modTcpSrc(short port) { + checkNotNull(port, "Src TCP port cannot be null"); + return new ModTransportPortInstruction(L4SubType.TCP_SRC, TpPort.tpPort(port)); + } + + /** + * Creates a TCP src modification. + * + * @param port the TCP port number to modify to + * @return a L4 modification + */ + public static L4ModificationInstruction modTcpSrc(TpPort port) { + checkNotNull(port, "Src TCP port cannot be null"); + return new ModTransportPortInstruction(L4SubType.TCP_SRC, port); + } + + /** + * Creates a TCP dst modification. + * + * @param port the TCP port number to modify to + * @return a L4 modification + * @deprecated in Drake release + */ + @Deprecated + public static L4ModificationInstruction modTcpDst(short port) { + checkNotNull(port, "Dst TCP port cannot be null"); + return new ModTransportPortInstruction(L4SubType.TCP_DST, TpPort.tpPort(port)); + } + + /** + * Creates a TCP dst modification. + * + * @param port the TCP port number to modify to + * @return a L4 modification + */ + public static L4ModificationInstruction modTcpDst(TpPort port) { + checkNotNull(port, "Dst TCP port cannot be null"); + return new ModTransportPortInstruction(L4SubType.TCP_DST, port); + } + + /** + * Creates a UDP src modification. + * + * @param port the UDP port number to modify to + * @return a L4 modification + * @deprecated in Drake release + */ + @Deprecated + public static L4ModificationInstruction modUdpSrc(short port) { + checkNotNull(port, "Src UDP port cannot be null"); + return new ModTransportPortInstruction(L4SubType.UDP_SRC, TpPort.tpPort(port)); + } + + /** + * Creates a UDP src modification. + * + * @param port the UDP port number to modify to + * @return a L4 modification + */ + public static L4ModificationInstruction modUdpSrc(TpPort port) { + checkNotNull(port, "Src UDP port cannot be null"); + return new ModTransportPortInstruction(L4SubType.UDP_SRC, port); + } + + /** + * Creates a UDP dst modification. + * + * @param port the UDP port number to modify to + * @return a L4 modification + * @deprecated in Drake release + */ + @Deprecated + public static L4ModificationInstruction modUdpDst(short port) { + checkNotNull(port, "Dst UDP port cannot be null"); + return new ModTransportPortInstruction(L4SubType.UDP_DST, TpPort.tpPort(port)); + } + + /** + * Creates a UDP dst modification. + * + * @param port the UDP port number to modify to + * @return a L4 modification + */ + public static L4ModificationInstruction modUdpDst(TpPort port) { + checkNotNull(port, "Dst UDP port cannot be null"); + return new ModTransportPortInstruction(L4SubType.UDP_DST, port); + } + + /** + * Drop instruction. + */ + public static final class DropInstruction implements Instruction { + + private DropInstruction() {} + + @Override + public Type type() { + return Type.DROP; + } + + @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 DropInstruction) { + return true; + } + return false; + } + } + + /** + * Output Instruction. + */ + public static final class OutputInstruction implements Instruction { + private final PortNumber port; + + private OutputInstruction(PortNumber port) { + this.port = port; + } + + public PortNumber port() { + return port; + } + + @Override + public Type type() { + return Type.OUTPUT; + } + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("port", port).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), port); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof OutputInstruction) { + OutputInstruction that = (OutputInstruction) obj; + return Objects.equals(port, that.port); + + } + return false; + } + } + + /** + * Group Instruction. + */ + public static final class GroupInstruction implements Instruction { + private final GroupId groupId; + + private GroupInstruction(GroupId groupId) { + this.groupId = groupId; + } + + public GroupId groupId() { + return groupId; + } + + @Override + public Type type() { + return Type.GROUP; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("group ID", groupId.id()).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), groupId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof GroupInstruction) { + GroupInstruction that = (GroupInstruction) obj; + return Objects.equals(groupId, that.groupId); + + } + return false; + } + } + + /** + * A meter instruction. + */ + public static final class MeterInstruction implements Instruction { + private final MeterId meterId; + + private MeterInstruction(MeterId meterId) { + this.meterId = meterId; + } + + public MeterId meterId() { + return meterId; + } + + @Override + public Type type() { + return Type.METER; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("meter ID", meterId.id()).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), meterId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof MeterInstruction) { + MeterInstruction that = (MeterInstruction) obj; + return Objects.equals(meterId, that.meterId); + + } + return false; + } + } + + /** + * Transition instruction. + */ + public static class TableTypeTransition implements Instruction { + private final Integer tableId; + + TableTypeTransition(Integer tableId) { + this.tableId = tableId; + } + + @Override + public Type type() { + return Type.TABLE; + } + + public Integer tableId() { + return this.tableId; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("tableId", this.tableId).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), tableId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof TableTypeTransition) { + TableTypeTransition that = (TableTypeTransition) obj; + return Objects.equals(tableId, that.tableId); + + } + return false; + } + } + + /** + * Metadata instruction. + */ + public static class MetadataInstruction implements Instruction { + private final long metadata; + private final long metadataMask; + + MetadataInstruction(long metadata, long metadataMask) { + this.metadata = metadata; + this.metadataMask = metadataMask; + } + + @Override + public Type type() { + return Type.METADATA; + } + + public long metadata() { + return this.metadata; + } + + public long metadataMask() { + return this.metadataMask; + } + + @Override + public String toString() { + return toStringHelper(type().toString()) + .add("metadata", Long.toHexString(this.metadata)) + .add("metadata mask", Long.toHexString(this.metadataMask)) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type().ordinal(), metadata, metadataMask); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof MetadataInstruction) { + MetadataInstruction that = (MetadataInstruction) obj; + return Objects.equals(metadata, that.metadata) && + Objects.equals(metadataMask, that.metadataMask); + + } + return false; + } + } + +} + + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L0ModificationInstruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L0ModificationInstruction.java new file mode 100644 index 00000000..a6e5903c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L0ModificationInstruction.java @@ -0,0 +1,139 @@ +/* + * Copyright 2014-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.instructions; + +import com.google.common.base.MoreObjects; +import org.onosproject.net.OchSignal; + +import static com.google.common.base.MoreObjects.toStringHelper; + +import java.util.Objects; + +public abstract class L0ModificationInstruction implements Instruction { + + /** + * Represents the type of traffic treatment. + */ + public enum L0SubType { + /** + * Lambda modification. + */ + LAMBDA, + /** + * OCh (Optical Channel) modification. + */ + OCH, + } + + public abstract L0SubType subtype(); + + @Override + public final Type type() { + return Type.L0MODIFICATION; + } + + /** + * Represents a L0 lambda modification instruction. + */ + public static final class ModLambdaInstruction extends L0ModificationInstruction { + + private final L0SubType subtype; + private final short lambda; + + ModLambdaInstruction(L0SubType subType, short lambda) { + this.subtype = subType; + this.lambda = lambda; + } + + @Override + public L0SubType subtype() { + return this.subtype; + } + + public short lambda() { + return this.lambda; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .add("lambda", lambda).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype, lambda); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ModLambdaInstruction) { + ModLambdaInstruction that = (ModLambdaInstruction) obj; + return Objects.equals(lambda, that.lambda) && + Objects.equals(subtype, that.subtype); + } + return false; + } + } + + /** + * Represents an L0 OCh (Optical Channel) modification instruction. + */ + public static final class ModOchSignalInstruction extends L0ModificationInstruction { + + private final OchSignal lambda; + + ModOchSignalInstruction(OchSignal lambda) { + this.lambda = lambda; + } + + @Override + public L0SubType subtype() { + return L0SubType.OCH; + } + + public OchSignal lambda() { + return lambda; + } + + @Override + public int hashCode() { + return Objects.hash(lambda); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ModOchSignalInstruction)) { + return false; + } + final ModOchSignalInstruction that = (ModOchSignalInstruction) obj; + return Objects.equals(this.lambda, that.lambda); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("lambda", lambda) + .toString(); + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L2ModificationInstruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L2ModificationInstruction.java new file mode 100644 index 00000000..0dbbb451 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L2ModificationInstruction.java @@ -0,0 +1,517 @@ +/* + * Copyright 2014-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.instructions; + +import org.onlab.packet.EthType; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.VlanId; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Abstraction of a single traffic treatment step. + */ +public abstract class L2ModificationInstruction implements Instruction { + + /** + * Represents the type of traffic treatment. + */ + public enum L2SubType { + /** + * Ether src modification. + */ + ETH_SRC, + + /** + * Ether dst modification. + */ + ETH_DST, + + /** + * VLAN id modification. + */ + VLAN_ID, + + /** + * VLAN priority modification. + */ + VLAN_PCP, + + /** + * MPLS Label modification. + */ + MPLS_LABEL, + + /** + * MPLS Push modification. + */ + MPLS_PUSH, + + /** + * MPLS Pop modification. + */ + MPLS_POP, + + /** + * MPLS TTL modification. + */ + DEC_MPLS_TTL, + + /** + * VLAN Pop modification. + */ + VLAN_POP, + + /** + * VLAN Push modification. + */ + VLAN_PUSH, + + /** + * Tunnel id modification. + */ + TUNNEL_ID, + + /** + * MPLS BOS instruction. + */ + MPLS_BOS + } + + // TODO: Create factory class 'Instructions' that will have various factory + // to create specific instructions. + + public abstract L2SubType subtype(); + + @Override + public final Type type() { + return Type.L2MODIFICATION; + } + + /** + * Represents a L2 src/dst modification instruction. + */ + public static final class ModEtherInstruction extends L2ModificationInstruction { + + private final L2SubType subtype; + private final MacAddress mac; + + ModEtherInstruction(L2SubType subType, MacAddress addr) { + + this.subtype = subType; + this.mac = addr; + } + + @Override + public L2SubType subtype() { + return this.subtype; + } + + public MacAddress mac() { + return this.mac; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .add("mac", mac).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype, mac); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ModEtherInstruction) { + ModEtherInstruction that = (ModEtherInstruction) obj; + return Objects.equals(mac, that.mac) && + Objects.equals(subtype, that.subtype); + } + return false; + } + } + + // TODO This instruction is reused for Pop-Mpls. Consider renaming. + public static final class PushHeaderInstructions extends + L2ModificationInstruction { + + + private final L2SubType subtype; + private final EthType ethernetType; // Ethernet type value: 16 bits + + PushHeaderInstructions(L2SubType subType, EthType ethernetType) { + this.subtype = subType; + this.ethernetType = ethernetType; + } + + public EthType ethernetType() { + return ethernetType; + } + + @Override + public L2SubType subtype() { + return this.subtype; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .add("ethernetType", ethernetType()) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype, ethernetType); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof PushHeaderInstructions) { + PushHeaderInstructions that = (PushHeaderInstructions) obj; + return Objects.equals(subtype, that.subtype) && + Objects.equals(this.ethernetType, that.ethernetType); + } + return false; + } + } + + + + /** + * Represents a VLAN id modification instruction. + */ + public static final class ModVlanIdInstruction extends L2ModificationInstruction { + + private final VlanId vlanId; + + ModVlanIdInstruction(VlanId vlanId) { + this.vlanId = vlanId; + } + + @Override + public L2SubType subtype() { + return L2SubType.VLAN_ID; + } + + public VlanId vlanId() { + return this.vlanId; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .add("id", vlanId).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype(), vlanId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ModVlanIdInstruction) { + ModVlanIdInstruction that = (ModVlanIdInstruction) obj; + return Objects.equals(vlanId, that.vlanId); + } + return false; + } + } + + /** + * Represents a VLAN PCP modification instruction. + */ + public static final class ModVlanPcpInstruction extends L2ModificationInstruction { + + private static final byte MASK = 0x7; + private final byte vlanPcp; + + ModVlanPcpInstruction(byte vlanPcp) { + this.vlanPcp = (byte) (vlanPcp & MASK); + } + + @Override + public L2SubType subtype() { + return L2SubType.VLAN_PCP; + } + + public byte vlanPcp() { + return this.vlanPcp; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .add("pcp", Long.toHexString(vlanPcp)).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype(), vlanPcp); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ModVlanPcpInstruction) { + ModVlanPcpInstruction that = (ModVlanPcpInstruction) obj; + return Objects.equals(vlanPcp, that.vlanPcp); + } + return false; + } + } + + /** + * Represents a VLAN POP modification instruction. + */ + public static final class PopVlanInstruction extends L2ModificationInstruction { + private final L2SubType subtype; + + PopVlanInstruction(L2SubType subType) { + this.subtype = subType; + } + + @Override + public L2SubType subtype() { + return subtype; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof PopVlanInstruction) { + PopVlanInstruction that = (PopVlanInstruction) obj; + return Objects.equals(subtype, that.subtype); + } + return false; + } + } + + /** + * Represents a MPLS label modification. + */ + public static final class ModMplsLabelInstruction + extends L2ModificationInstruction { + + private final MplsLabel mplsLabel; + + ModMplsLabelInstruction(MplsLabel mplsLabel) { + this.mplsLabel = mplsLabel; + } + + /** + * @deprecated in Drake Release. + * @return integer value of label + */ + // Consider changing return value to MplsLabel + // after deprecation process so that it'll be symmetric to + // MplsCriterion#label() + @Deprecated + public Integer label() { + return mplsLabel.toInt(); + } + + public MplsLabel mplsLabel() { + return mplsLabel; + } + + @Override + public L2SubType subtype() { + return L2SubType.MPLS_LABEL; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .add("mpls", mplsLabel).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype(), mplsLabel); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ModMplsLabelInstruction) { + ModMplsLabelInstruction that = (ModMplsLabelInstruction) obj; + return Objects.equals(mplsLabel, that.mplsLabel); + } + return false; + } + } + + /** + * Represents a MPLS BOS modification. + */ + public static final class ModMplsBosInstruction + extends L2ModificationInstruction { + + private final boolean mplsBos; + + ModMplsBosInstruction(boolean mplsBos) { + this.mplsBos = mplsBos; + } + + public boolean mplsBos() { + return mplsBos; + } + + @Override + public L2SubType subtype() { + return L2SubType.MPLS_BOS; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()).add("bos", mplsBos) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype(), mplsBos); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ModMplsBosInstruction) { + ModMplsBosInstruction that = (ModMplsBosInstruction) obj; + return Objects.equals(mplsBos, that.mplsBos()); + } + return false; + } + } + + /** + * Represents a MPLS TTL modification. + */ + public static final class ModMplsTtlInstruction + extends L2ModificationInstruction { + + ModMplsTtlInstruction() { + } + + @Override + public L2SubType subtype() { + return L2SubType.DEC_MPLS_TTL; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ModMplsTtlInstruction) { + return true; + } + return false; + } + } + + /** + * Represents a Tunnel id modification. + */ + public static final class ModTunnelIdInstruction + extends L2ModificationInstruction { + + private final long tunnelId; + + ModTunnelIdInstruction(long tunnelId) { + this.tunnelId = tunnelId; + } + + public long tunnelId() { + return this.tunnelId; + } + + @Override + public L2SubType subtype() { + return L2SubType.TUNNEL_ID; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .add("id", Long.toHexString(tunnelId)) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype(), tunnelId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ModTunnelIdInstruction) { + ModTunnelIdInstruction that = (ModTunnelIdInstruction) obj; + return Objects.equals(tunnelId, that.tunnelId); + } + return false; + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L3ModificationInstruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L3ModificationInstruction.java new file mode 100644 index 00000000..41819504 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L3ModificationInstruction.java @@ -0,0 +1,231 @@ +/* + * Copyright 2014-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.instructions; + +import static com.google.common.base.MoreObjects.toStringHelper; + +import java.util.Objects; + +import org.onlab.packet.IpAddress; + +/** + * Abstraction of a single traffic treatment step. + */ +public abstract class L3ModificationInstruction implements Instruction { + + /** + * Represents the type of traffic treatment. + */ + public enum L3SubType { + /** + * IPv4 src modification. + */ + IPV4_SRC, + + /** + * IPv4 dst modification. + */ + IPV4_DST, + + /** + * IPv6 src modification. + */ + IPV6_SRC, + + /** + * IPv6 dst modification. + */ + IPV6_DST, + + /** + * IPv6 flow label modification. + */ + IPV6_FLABEL, + + /** + * Decrement TTL. + */ + DEC_TTL, + + /** + * Copy TTL out. + */ + TTL_OUT, + + /** + * Copy TTL in. + */ + TTL_IN + + //TODO: remaining types + } + + /** + * Returns the subtype of the modification instruction. + * @return type of instruction + */ + public abstract L3SubType subtype(); + + @Override + public final Type type() { + return Type.L3MODIFICATION; + } + + /** + * Represents a L3 src/dst modification instruction. + */ + public static final class ModIPInstruction extends L3ModificationInstruction { + + private final L3SubType subtype; + private final IpAddress ip; + + ModIPInstruction(L3SubType subType, IpAddress addr) { + + this.subtype = subType; + this.ip = addr; + } + + @Override + public L3SubType subtype() { + return this.subtype; + } + + public IpAddress ip() { + return this.ip; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .add("ip", ip).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype(), ip); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ModIPInstruction) { + ModIPInstruction that = (ModIPInstruction) obj; + return Objects.equals(ip, that.ip) && + Objects.equals(this.subtype(), that.subtype()); + } + return false; + } + } + + /** + * Represents a L3 IPv6 Flow Label (RFC 6437) modification instruction + * (20 bits unsigned integer). + */ + public static final class ModIPv6FlowLabelInstruction + extends L3ModificationInstruction { + private static final int MASK = 0xfffff; + private final int flowLabel; // IPv6 flow label: 20 bits + + /** + * Creates a new flow mod instruction. + * + * @param flowLabel the IPv6 flow label to set in the treatment (20 bits) + */ + ModIPv6FlowLabelInstruction(int flowLabel) { + this.flowLabel = flowLabel & MASK; + } + + @Override + public L3SubType subtype() { + return L3SubType.IPV6_FLABEL; + } + + /** + * Gets the IPv6 flow label to set in the treatment. + * + * @return the IPv6 flow label to set in the treatment (20 bits) + */ + public int flowLabel() { + return this.flowLabel; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .add("flowLabel", Long.toHexString(flowLabel)).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype(), flowLabel); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ModIPv6FlowLabelInstruction) { + ModIPv6FlowLabelInstruction that = + (ModIPv6FlowLabelInstruction) obj; + return Objects.equals(flowLabel, that.flowLabel); + } + return false; + } + } + + /** + * Represents a L3 TTL modification instruction. + */ + public static final class ModTtlInstruction extends L3ModificationInstruction { + + private final L3SubType subtype; + + ModTtlInstruction(L3SubType subtype) { + this.subtype = subtype; + } + + @Override + public L3SubType subtype() { + return this.subtype; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ModTtlInstruction) { + ModTtlInstruction that = (ModTtlInstruction) obj; + return Objects.equals(this.subtype(), that.subtype()); + } + return false; + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L4ModificationInstruction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L4ModificationInstruction.java new file mode 100644 index 00000000..441a2c5f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/L4ModificationInstruction.java @@ -0,0 +1,114 @@ +/* + * Copyright 2014-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.instructions; + +import org.onlab.packet.TpPort; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Abstraction of a single traffic treatment step. + */ +public abstract class L4ModificationInstruction implements Instruction { + + /** + * Represents the type of traffic treatment. + */ + public enum L4SubType { + /** + * TCP src modification. + */ + TCP_SRC, + + /** + * TCP dst modification. + */ + TCP_DST, + + /** + * UDP src modification. + */ + UDP_SRC, + + /** + * UDP dst modification. + */ + UDP_DST + + //TODO: remaining types + } + + /** + * Returns the subtype of the modification instruction. + * + * @return type of instruction + */ + public abstract L4SubType subtype(); + + @Override + public Type type() { + return Type.L4MODIFICATION; + } + + /** + * Represents a L4 src/dst modification instruction. + */ + public static final class ModTransportPortInstruction extends L4ModificationInstruction { + + private final L4SubType subtype; + private final TpPort port; + + public ModTransportPortInstruction(L4SubType subtype, TpPort port) { + this.subtype = subtype; + this.port = port; + } + + @Override + public L4SubType subtype() { + return this.subtype; + } + + public TpPort port() { + return this.port; + } + + @Override + public String toString() { + return toStringHelper(subtype().toString()) + .add("port", port).toString(); + } + + @Override + public int hashCode() { + return Objects.hash(type(), subtype(), port); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ModTransportPortInstruction) { + ModTransportPortInstruction that = (ModTransportPortInstruction) obj; + return Objects.equals(port, that.port) && + Objects.equals(this.subtype(), that.subtype()); + } + return false; + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/package-info.java new file mode 100644 index 00000000..65f58a40 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/instructions/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Traffic treatment model. + */ +package org.onosproject.net.flow.instructions; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/package-info.java new file mode 100644 index 00000000..6068b6f2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flow/package-info.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014-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. + */ + +/** + * Flow rule model & related services API definitions. + * + *

+ * The figure below depicts the general interactions between different + * components of the intent subsystem.
+ * ONOS flow rule subsystem design + *

+ */ +package org.onosproject.net.flow; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java new file mode 100644 index 00000000..7b5924fb --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java @@ -0,0 +1,239 @@ +/* + * 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.flowobjective; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableList; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.flow.criteria.Criteria; +import org.onosproject.net.flow.criteria.Criterion; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default implementation of a filtering objective. + */ +@Beta +public final class DefaultFilteringObjective implements FilteringObjective { + + + private final Type type; + private final boolean permanent; + private final int timeout; + private final ApplicationId appId; + private final int priority; + private final Criterion key; + private final List conditions; + private final int id; + private final Operation op; + private final Optional context; + + private DefaultFilteringObjective(Builder builder) { + this.key = builder.key; + this.type = builder.type; + this.permanent = builder.permanent; + this.timeout = builder.timeout; + this.appId = builder.appId; + this.priority = builder.priority; + this.conditions = builder.conditions; + this.op = builder.op; + this.context = Optional.ofNullable(builder.context); + + this.id = Objects.hash(type, key, conditions, permanent, + timeout, appId, priority); + } + + @Override + public Criterion key() { + return key; + } + + @Override + public Type type() { + return this.type; + } + + @Override + public Collection conditions() { + return conditions; + } + + @Override + public int id() { + return id; + } + + @Override + public int priority() { + return priority; + } + + @Override + public ApplicationId appId() { + return appId; + } + + @Override + public int timeout() { + return timeout; + } + + @Override + public boolean permanent() { + return permanent; + } + + @Override + public Operation op() { + return op; + } + + @Override + public Optional context() { + return context; + } + + /** + * Returns a new builder. + * + * @return new builder + */ + public static Builder builder() { + return new Builder(); + } + + + public static final class Builder implements FilteringObjective.Builder { + private final ImmutableList.Builder listBuilder + = ImmutableList.builder(); + + private Type type; + private boolean permanent = DEFAULT_PERMANENT; + private int timeout = DEFAULT_TIMEOUT; + private ApplicationId appId; + private int priority = DEFAULT_PRIORITY; + private Criterion key = Criteria.dummy(); + private List conditions; + private Operation op; + private ObjectiveContext context; + + @Override + public Builder withKey(Criterion key) { + this.key = key; + return this; + } + + @Override + public Builder addCondition(Criterion criterion) { + listBuilder.add(criterion); + return this; + } + + @Override + public Builder permit() { + this.type = Type.PERMIT; + return this; + } + + @Override + public Builder deny() { + this.type = Type.DENY; + return this; + } + + @Override + public Builder makeTemporary(int timeout) { + this.timeout = timeout; + permanent = false; + return this; + } + + @Override + public Builder makePermanent() { + permanent = true; + return this; + } + + @Override + public Builder fromApp(ApplicationId appId) { + this.appId = appId; + return this; + } + + @Override + public Builder withPriority(int priority) { + this.priority = priority; + return this; + } + + @Override + public FilteringObjective add() { + conditions = listBuilder.build(); + op = Operation.ADD; + checkNotNull(type, "Must have a type."); + checkArgument(!conditions.isEmpty(), "Must have at least one condition."); + checkNotNull(appId, "Must supply an application id"); + + return new DefaultFilteringObjective(this); + + } + + @Override + public FilteringObjective remove() { + conditions = listBuilder.build(); + checkNotNull(type, "Must have a type."); + checkArgument(!conditions.isEmpty(), "Must have at least one condition."); + checkNotNull(appId, "Must supply an application id"); + op = Operation.REMOVE; + + return new DefaultFilteringObjective(this); + + } + + @Override + public FilteringObjective add(ObjectiveContext context) { + conditions = listBuilder.build(); + checkNotNull(type, "Must have a type."); + checkArgument(!conditions.isEmpty(), "Must have at least one condition."); + checkNotNull(appId, "Must supply an application id"); + op = Operation.ADD; + this.context = context; + + return new DefaultFilteringObjective(this); + } + + @Override + public FilteringObjective remove(ObjectiveContext context) { + conditions = listBuilder.build(); + checkNotNull(type, "Must have a type."); + checkArgument(!conditions.isEmpty(), "Must have at least one condition."); + checkNotNull(appId, "Must supply an application id"); + op = Operation.REMOVE; + this.context = context; + + return new DefaultFilteringObjective(this); + } + + + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultForwardingObjective.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultForwardingObjective.java new file mode 100644 index 00000000..0abf5abe --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultForwardingObjective.java @@ -0,0 +1,241 @@ +/* + * 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.flowobjective; + +import com.google.common.annotations.Beta; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import java.util.Objects; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default implementation of a forwarding objective. + */ +@Beta +public final class DefaultForwardingObjective implements ForwardingObjective { + + private final TrafficSelector selector; + private final Flag flag; + private final boolean permanent; + private final int timeout; + private final ApplicationId appId; + private final int priority; + private final Integer nextId; + private final TrafficTreatment treatment; + private final Operation op; + private final Optional context; + + private final int id; + + private DefaultForwardingObjective(Builder builder) { + this.selector = builder.selector; + this.flag = builder.flag; + this.permanent = builder.permanent; + this.timeout = builder.timeout; + this.appId = builder.appId; + this.priority = builder.priority; + this.nextId = builder.nextId; + this.treatment = builder.treatment; + this.op = builder.op; + this.context = Optional.ofNullable(builder.context); + + this.id = Objects.hash(selector, flag, permanent, + timeout, appId, priority, nextId, + treatment, op); + } + + + @Override + public TrafficSelector selector() { + return selector; + } + + @Override + public Integer nextId() { + return nextId; + } + + @Override + public TrafficTreatment treatment() { + return treatment; + } + + + @Override + public Flag flag() { + return flag; + } + + @Override + public int id() { + return id; + } + + @Override + public int priority() { + return priority; + } + + @Override + public ApplicationId appId() { + return appId; + } + + @Override + public int timeout() { + return timeout; + } + + @Override + public boolean permanent() { + return permanent; + } + + @Override + public Operation op() { + return op; + } + + @Override + public Optional context() { + return context; + } + + /** + * Returns a new builder. + * + * @return new builder + */ + public static Builder builder() { + return new Builder(); + } + + public static final class Builder implements ForwardingObjective.Builder { + + private TrafficSelector selector; + private Flag flag; + private boolean permanent = DEFAULT_PERMANENT; + private int timeout = DEFAULT_TIMEOUT; + private int priority = DEFAULT_PRIORITY; + private ApplicationId appId; + private Integer nextId; + private TrafficTreatment treatment; + private Operation op; + private ObjectiveContext context; + + @Override + public Builder withSelector(TrafficSelector selector) { + this.selector = selector; + return this; + } + + @Override + public Builder nextStep(int nextId) { + this.nextId = nextId; + return this; + } + + @Override + public Builder withTreatment(TrafficTreatment treatment) { + this.treatment = treatment; + return this; + } + + @Override + public Builder withFlag(Flag flag) { + this.flag = flag; + return this; + } + + @Override + public Builder makeTemporary(int timeout) { + this.timeout = timeout; + this.permanent = false; + return this; + } + + @Override + public Builder makePermanent() { + this.permanent = true; + return this; + } + + @Override + public Builder fromApp(ApplicationId appId) { + this.appId = appId; + return this; + } + + @Override + public Builder withPriority(int priority) { + this.priority = priority; + return this; + } + + @Override + public ForwardingObjective add() { + checkNotNull(selector, "Must have a selector"); + checkNotNull(flag, "A flag must be set"); + checkArgument(nextId != null || treatment != null, "Must supply at " + + "least a treatment and/or a nextId"); + checkNotNull(appId, "Must supply an application id"); + op = Operation.ADD; + return new DefaultForwardingObjective(this); + } + + @Override + public ForwardingObjective remove() { + checkNotNull(selector, "Must have a selector"); + checkNotNull(flag, "A flag must be set"); + checkArgument(nextId != null || treatment != null, "Must supply at " + + "least a treatment and/or a nextId"); + checkNotNull(appId, "Must supply an application id"); + op = Operation.REMOVE; + return new DefaultForwardingObjective(this); + } + + @Override + public ForwardingObjective add(ObjectiveContext context) { + checkNotNull(selector, "Must have a selector"); + checkNotNull(flag, "A flag must be set"); + checkArgument(nextId != null || treatment != null, "Must supply at " + + "least a treatment and/or a nextId"); + checkNotNull(appId, "Must supply an application id"); + op = Operation.ADD; + this.context = context; + + return new DefaultForwardingObjective(this); + } + + @Override + public ForwardingObjective remove(ObjectiveContext context) { + checkNotNull(selector, "Must have a selector"); + checkNotNull(flag, "A flag must be set"); + checkArgument(nextId != null || treatment != null, "Must supply at " + + "least a treatment and/or a nextId"); + checkNotNull(appId, "Must supply an application id"); + op = Operation.REMOVE; + this.context = context; + + return new DefaultForwardingObjective(this); + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java new file mode 100644 index 00000000..20e89295 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java @@ -0,0 +1,222 @@ +/* + * 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.flowobjective; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableList; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.flow.TrafficTreatment; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Default implementation of a next objective. + */ +@Beta +public final class DefaultNextObjective implements NextObjective { + + private final List treatments; + private final ApplicationId appId; + private final Type type; + private final Integer id; + private final Operation op; + private final Optional context; + + private DefaultNextObjective(Builder builder) { + this.treatments = builder.treatments; + this.appId = builder.appId; + this.type = builder.type; + this.id = builder.id; + this.op = builder.op; + this.context = Optional.ofNullable(builder.context); + } + + @Override + public Collection next() { + return treatments; + } + + @Override + public Type type() { + return type; + } + + @Override + public int id() { + return id; + } + + @Override + public int priority() { + return 0; + } + + @Override + public ApplicationId appId() { + return appId; + } + + @Override + public int timeout() { + return 0; + } + + @Override + public boolean permanent() { + return false; + } + + @Override + public Operation op() { + return op; + } + + @Override + public Optional context() { + return context; + } + + /** + * Returns a new builder. + * + * @return new builder + */ + public static Builder builder() { + return new Builder(); + } + + public static final class Builder implements NextObjective.Builder { + + private ApplicationId appId; + private Type type; + private Integer id; + private List treatments; + private Operation op; + private ObjectiveContext context; + + private final ImmutableList.Builder listBuilder + = ImmutableList.builder(); + + @Override + public Builder withId(int nextId) { + this.id = nextId; + return this; + } + + @Override + public Builder withType(Type type) { + this.type = type; + return this; + } + + @Override + public Builder addTreatment(TrafficTreatment treatment) { + listBuilder.add(treatment); + return this; + } + + /** + * Noop. This method has no effect. + * + * @param timeout a timeout + * @return a next objective builder + */ + @Override + public Builder makeTemporary(int timeout) { + return this; + } + + /** + * Noop. This method has no effect. + * + * @return a next objective builder + */ + @Override + public Builder makePermanent() { + return this; + } + + @Override + public Builder fromApp(ApplicationId appId) { + this.appId = appId; + return this; + } + + /** + * Noop. This method has no effect. + * + * @param priority an integer + * @return a next objective builder + */ + @Override + public Builder withPriority(int priority) { + return this; + } + + @Override + public NextObjective add() { + treatments = listBuilder.build(); + op = Operation.ADD; + checkNotNull(appId, "Must supply an application id"); + checkNotNull(id, "id cannot be null"); + checkNotNull(type, "The type cannot be null"); + checkArgument(!treatments.isEmpty(), "Must have at least one treatment"); + + return new DefaultNextObjective(this); + } + + @Override + public NextObjective remove() { + treatments = listBuilder.build(); + op = Operation.REMOVE; + checkNotNull(appId, "Must supply an application id"); + checkNotNull(id, "id cannot be null"); + checkNotNull(type, "The type cannot be null"); + + return new DefaultNextObjective(this); + } + + @Override + public NextObjective add(ObjectiveContext context) { + treatments = listBuilder.build(); + op = Operation.ADD; + this.context = context; + checkNotNull(appId, "Must supply an application id"); + checkNotNull(id, "id cannot be null"); + checkNotNull(type, "The type cannot be null"); + checkArgument(!treatments.isEmpty(), "Must have at least one treatment"); + + return new DefaultNextObjective(this); + } + + @Override + public NextObjective remove(ObjectiveContext context) { + treatments = listBuilder.build(); + op = Operation.REMOVE; + this.context = context; + checkNotNull(appId, "Must supply an application id"); + checkNotNull(id, "id cannot be null"); + checkNotNull(type, "The type cannot be null"); + + return new DefaultNextObjective(this); + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java new file mode 100644 index 00000000..58304571 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java @@ -0,0 +1,158 @@ +/* + * 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.flowobjective; + +import com.google.common.annotations.Beta; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.flow.criteria.Criterion; + +import java.util.Collection; + +/** + * Represents a filtering flow objective. Each filtering flow objective + * is made up of a key (criterion) to a set of criteria. Using this information + * a pipeline aware driver will decide how this objective should be mapped + * to the specific device pipeline. For example, consider the following + * filtering objective: + * + * portX -> {MAC1, IP1, MAC2} + * + * The driver could decide to pass L3 packet to the L3 table and L2 packets to + * the L2 table for packets arriving on portX. + * + * Filtering objectives do not only represent what should be permitted into the + * pipeline but can also be used to deny or drop unwanted packets by specifying + * the appropriate type of filtering objective. It is also important to note + * that submitting a filtering objective does not necessarily result in rules + * programmed at the switch, the driver is free to decide when these rules are + * programmed. For example, a filtering rule may only be programmed once a + * corresponding forwarding objective has been received. + */ +@Beta +public interface FilteringObjective extends Objective { + + enum Type { + /** + * Enables the filtering condition. + */ + PERMIT, + + /** + * Disables the filtering condition. + */ + DENY + } + + /** + * Obtain the key for this filter. + * + * @return a criterion + */ + Criterion key(); + + /** + * Obtain this filtering type. + * + * @return the type + */ + Type type(); + + /** + * The set of conditions the filter must provision at the device. + * + * @return a collection of criteria + */ + Collection conditions(); + + /** + * Builder of Filtering objective entities. + */ + interface Builder extends Objective.Builder { + + /** + * Specify the key for the filter. + * + * @param key a criterion + * @return a filter objective builder + */ + Builder withKey(Criterion key); + + /** + * Add a filtering condition. + * + * @param criterion new criterion + * @return a filtering builder + */ + Builder addCondition(Criterion criterion); + + /** + * Permit this filtering condition set. + * + * @return a filtering builder + */ + Builder permit(); + + /** + * Deny this filtering condition set. + * + * @return a filtering builder + */ + Builder deny(); + + /** + * Assigns an application id. + * + * @param appId an application id + * @return a filtering builder + */ + Builder fromApp(ApplicationId appId); + + /** + * Builds the filtering objective that will be added. + * + * @return a filtering objective + */ + FilteringObjective add(); + + /** + * Builds the filtering objective that will be removed. + * + * @return a filtering objective. + */ + FilteringObjective remove(); + + /** + * Builds the filtering objective that will be added. + * The context will be used to notify the calling application. + * + * @param context an objective context + * @return a filtering objective + */ + FilteringObjective add(ObjectiveContext context); + + /** + * Builds the filtering objective that will be removed. + * The context will be used to notify the calling application. + * + * @param context an objective context + * @return a filtering objective + */ + FilteringObjective remove(ObjectiveContext context); + + + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveService.java new file mode 100644 index 00000000..d3254151 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveService.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.flowobjective; + +import com.google.common.annotations.Beta; +import org.onosproject.net.DeviceId; + +/** + * Service for programming data plane flow rules in manner independent of + * specific device table pipeline configuration. + */ +@Beta +public interface FlowObjectiveService { + + /** + * Installs the filtering rules onto the specified device. + * + * @param deviceId device identifier + * @param filteringObjective the filtering objective + */ + void filter(DeviceId deviceId, FilteringObjective filteringObjective); + + /** + * Installs the forwarding rules onto the specified device. + * + * @param deviceId device identifier + * @param forwardingObjective the forwarding objective + */ + void forward(DeviceId deviceId, ForwardingObjective forwardingObjective); + + /** + * Installs the next hop elements into the specified device. + * + * @param deviceId device identifier + * @param nextObjective a next objective + */ + void next(DeviceId deviceId, NextObjective nextObjective); + + /** + * Obtains a globally unique next objective. + * + * @return an integer + */ + int allocateNextId(); + + /** + * Installs the filtering rules onto the specified device. + * + * @param policy policy expression + */ + void initPolicy(String policy); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveStore.java new file mode 100644 index 00000000..ecf5d733 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveStore.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.net.flowobjective; + +import com.google.common.annotations.Beta; +import org.onosproject.net.behaviour.NextGroup; +import org.onosproject.store.Store; + +/** + * The flow objective store. + */ +@Beta +public interface FlowObjectiveStore + extends Store { + + /** + * Adds a NextGroup to the store. + * + * @param nextId an integer + * @param group a next group opaque object + */ + void putNextGroup(Integer nextId, NextGroup group); + + /** + * Fetch a next group from the store. + * @param nextId an integer + * @return a next group + */ + NextGroup getNextGroup(Integer nextId); + + /** + * Allocates a next objective id. This id is globally unique + * + * @return an integer + */ + int allocateNextId(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveStoreDelegate.java new file mode 100644 index 00000000..2189af1b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveStoreDelegate.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.flowobjective; + +import com.google.common.annotations.Beta; +import org.onosproject.store.StoreDelegate; + +/** + * Flow Objective store delegate abstraction. + */ +@Beta +public interface FlowObjectiveStoreDelegate extends StoreDelegate { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ForwardingObjective.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ForwardingObjective.java new file mode 100644 index 00000000..9857a710 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ForwardingObjective.java @@ -0,0 +1,158 @@ +/* + * 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.flowobjective; + +import com.google.common.annotations.Beta; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +/** + * Represents a description of which types of traffic need to + * be forwarded through the device. A forwarding objective may + * result in multiple rules at the device. There are two main types + * of forwarding objectives: + * + * - Versatile + * - Specific + * + * A versatile forwarding objective represents a composite rule that matches + * two or more header fields. The use of versatile usually indicates that this + * rule should be inserted in its entirety into the ACL table. Although, + * drivers for some devices are free to implement this differently. + * + * A specific forwarding objective represents a specific rule matching one or + * more header fields. The installation of this rule may result in several rules + * at the device. For example, one per table type. + */ +@Beta +public interface ForwardingObjective extends Objective { + + /** + * Represents whether this objective is monolithic or + * may be broken down into parts. + */ + enum Flag { + /** + * A decomposable objective. + */ + SPECIFIC, + + /** + * A monolithic objective. + */ + VERSATILE + } + + /** + * Obtain the selector for this objective. + * + * @return a traffic selector + */ + TrafficSelector selector(); + + /** + * Obtain the traffic treatment for this objective. Mutually exclusive with + * 'treatment'. + * + * @return an integer + */ + Integer nextId(); + + /** + * A traffic treatment for this forwarding objective. Mutually exclusive + * with a nextId. + * + * @return a traffic treatment + */ + TrafficTreatment treatment(); + + /** + * Obtain the type of this objective. + * + * @return a flag type + */ + Flag flag(); + + /** + * A forwarding objective builder. + */ + interface Builder extends Objective.Builder { + + /** + * Assigns a selector to the forwarding objective. + * + * @param selector a traffic selector + * @return a forwarding objective builder + */ + Builder withSelector(TrafficSelector selector); + + /** + * Assigns a next step to the forwarding objective. + * + * @param nextId a next objective id. + * @return a forwarding objective builder + */ + Builder nextStep(int nextId); + + /** + * Assigns the treatment for this forwarding objective. + * + * @param treatment a traffic treatment + * @return a forwarding objective + */ + Builder withTreatment(TrafficTreatment treatment); + + /** + * Assigns the flag to the forwarding objective. + * + * @param flag a flag + * @return a forwarding objective builder + */ + Builder withFlag(Flag flag); + + /** + * Builds the forwarding objective that will be added. + * + * @return a forwarding objective + */ + ForwardingObjective add(); + + /** + * Builds the forwarding objective that will be removed. + * + * @return a forwarding objective. + */ + ForwardingObjective remove(); + + /** + * Builds the forwarding objective that will be added. + * The context will be used to notify the calling application. + * + * @param context an objective context + * @return a forwarding objective + */ + ForwardingObjective add(ObjectiveContext context); + + /** + * Builds the forwarding objective that will be removed. + * The context will be used to notify the calling application. + * + * @param context an objective context + * @return a forwarding objective + */ + ForwardingObjective remove(ObjectiveContext context); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/NextObjective.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/NextObjective.java new file mode 100644 index 00000000..1350d7a1 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/NextObjective.java @@ -0,0 +1,167 @@ +/* + * 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.flowobjective; + +import com.google.common.annotations.Beta; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.flow.TrafficTreatment; + +import java.util.Collection; + +/** + * Represents a nexthop which will be translated by a driver + * into the appropriate group or actions needed to implement + * the egress function. + * + * A next objective is made up of a collection of traffic treatments + * associated with a type. These types are: + * + * - Hashed + * - Broadcast + * - Failover + * - Simple + * + * These types will indicate to the driver what the intended behaviour is. + * For example, a broadcast next objective with a collection of output + * treatments will indicate to a driver that all output actions are expected + * to be executed simultaneously. The driver is then free to implement this + * as a group or a simple action list. + */ +@Beta +public interface NextObjective extends Objective { + + /** + * Represents the type of next phase to build. + */ + enum Type { + /** + * A hashed packet processing. + */ + HASHED, + + /** + * Broadcast packet process. + */ + BROADCAST, + + /** + * Failover handling. + */ + FAILOVER, + + /** + * Simple processing. Could be a group or a treatment. + */ + SIMPLE + } + + /** + * The collection of treatments that need to be applied to a set of traffic. + * + * @return a collection of traffic treatments + */ + Collection next(); + + /** + * The type of operation that will be applied to the traffic using the collection + * of treatments. + * + * @return a type + */ + Type type(); + + /** + * A next step builder. + */ + interface Builder extends Objective.Builder { + + /** + * Specifies the id for this next objective. + * + * @param nextId an integer + * @return a next objective builder + */ + Builder withId(int nextId); + + /** + * Sets the type of next step. + * + * @param type a type + * @return a next step builder + */ + Builder withType(Type type); + + /** + * Adds a treatment to this next step. + * + * @param treatment a traffic treatment + * @return a next step builder + */ + Builder addTreatment(TrafficTreatment treatment); + + /** + * Specifies the application which applied the filter. + * + * @param appId an application id + * @return an objective builder + */ + @Override + Builder fromApp(ApplicationId appId); + + /** + * Sets the priority for this objective. + * + * @param priority an integer + * @return an objective builder + */ + @Override + Builder withPriority(int priority); + + /** + * Builds the next objective that will be added. + * + * @return a next objective + */ + NextObjective add(); + + /** + * Builds the next objective that will be removed. + * + * @return a next objective. + */ + NextObjective remove(); + + /** + * Builds the next objective that will be added. + * The context will be used to notify the calling application. + * + * @param context an objective context + * @return a next objective + */ + NextObjective add(ObjectiveContext context); + + /** + * Builds the next objective that will be removed. + * The context will be used to notify the calling application. + * + * @param context an objective context + * @return a next objective + */ + NextObjective remove(ObjectiveContext context); + + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/Objective.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/Objective.java new file mode 100644 index 00000000..090c298c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/Objective.java @@ -0,0 +1,134 @@ +/* + * 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.flowobjective; + +import com.google.common.annotations.Beta; +import org.onosproject.core.ApplicationId; + +import java.util.Optional; + +/** + * Base representation of an flow description. + */ +@Beta +public interface Objective { + + static final boolean DEFAULT_PERMANENT = true; + static final int DEFAULT_TIMEOUT = 0; + static final int DEFAULT_PRIORITY = 32768; + + /** + * Type of operation. + */ + enum Operation { + /** + * Adds the objective. + */ + ADD, + + /** + * Removes the objective. + */ + REMOVE + } + + /** + * An identifier for this objective. + * + * @return an integer + */ + int id(); + + /** + * The priority for this objective. + * + * @return an integer + */ + int priority(); + + /** + * The application which applied this objective. + * + * @return an application id + */ + ApplicationId appId(); + + /** + * The timeout for this objective. + * + * @return an integer + */ + int timeout(); + + /** + * Whether this objective is permanent. + * + * @return a boolean + */ + boolean permanent(); + + /** + * The type of operation for this objective. + * + * @return an operation + */ + Operation op(); + + /** + * Obtains an optional context. + * + * @return optional; which will be empty if there is no context. + * Otherwise it will return the context. + */ + Optional context(); + + /** + * An objective builder. + */ + interface Builder { + /** + * Makes the filtering objective temporary. + * + * @param timeout a timeout + * @return an objective builder + */ + Builder makeTemporary(int timeout); + + /** + * Makes the filtering objective permanent. + * + * @return an objective builder + */ + Builder makePermanent(); + + /** + * Specifies the application which applied the filter. + * + * @param appId an application id + * @return an objective builder + */ + Builder fromApp(ApplicationId appId); + + /** + * Sets the priority for this objective. + * + * @param priority an integer + * @return an objective builder + */ + Builder withPriority(int priority); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ObjectiveContext.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ObjectiveContext.java new file mode 100644 index 00000000..f3d23e4a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ObjectiveContext.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.flowobjective; + +import com.google.common.annotations.Beta; + +/** + * The context of a objective that will become the subject of + * the notification. + *

+ * Implementations of this class must be serializable. + *

+ */ +@Beta +public interface ObjectiveContext { + + /** + * Invoked on successful execution of the flow objective. + * + * @param objective objective to execute + */ + default void onSuccess(Objective objective) { + } + + /** + * Invoked when error is encountered while executing the flow objective. + * + * @param objective objective to execute + * @param error error encountered + */ + default void onError(Objective objective, ObjectiveError error) { + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ObjectiveError.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ObjectiveError.java new file mode 100644 index 00000000..fd159d7e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ObjectiveError.java @@ -0,0 +1,60 @@ +/* + * 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.flowobjective; + +import com.google.common.annotations.Beta; + +/** + * Represents the set of errors possible when processing an objective. + */ +@Beta +public enum ObjectiveError { + + /** + * The driver processing this objective does not know how to process it. + */ + UNSUPPORTED, + + /** + * The flow installation for this objective failed. + */ + FLOWINSTALLATIONFAILED, + + /** + * THe group installation for this objective failed. + */ + GROUPINSTALLATIONFAILED, + + /** + * The group was reported as installed but is missing. + */ + GROUPMISSING, + + /** + * The device was not available to install objectives to. + */ + DEVICEMISSING, + + /** + * Incorrect Objective parameters passed in by the caller. + */ + BADPARAMS, + + /** + * An unknown error occurred. + */ + UNKNOWN +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ObjectiveEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ObjectiveEvent.java new file mode 100644 index 00000000..c6937e31 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/ObjectiveEvent.java @@ -0,0 +1,64 @@ +/* + * 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.flowobjective; + +import com.google.common.annotations.Beta; +import org.onosproject.event.AbstractEvent; + +/** + * Describes a objective event. + */ +@Beta +public class ObjectiveEvent extends AbstractEvent { + + /** + * Type of objective events. + */ + public enum Type { + /** + * Signifies that the objective has been added to the store. + */ + ADD, + + /** + * Signifies that the objective has been removed. + */ + REMOVE + } + + /** + * Creates an event of the given type for the specified objective id. + * + * @param type the type of the event + * @param objective the objective id the event is about + */ + public ObjectiveEvent(Type type, Integer objective) { + super(type, objective); + } + + /** + * Creates an event of the given type for the specified objective id at the given + * time. + * + * @param type the type of the event + * @param objective the objective id the event is about + * @param time the time of the event + */ + public ObjectiveEvent(Type type, Integer objective, long time) { + super(type, objective, time); + } +} + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/package-info.java new file mode 100644 index 00000000..105f7b59 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/flowobjective/package-info.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + * Abstractions for objective-based flow programming of data plane without + * requiring device pipeline structure awareness.  This subsystem is + * experimental and its interfaces will change in the upcoming release. + */ +package org.onosproject.net.flowobjective; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroup.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroup.java new file mode 100644 index 00000000..546a4513 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroup.java @@ -0,0 +1,229 @@ +/* + * 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.group; + +import static com.google.common.base.MoreObjects.toStringHelper; + +import java.util.Objects; + +import org.onosproject.core.GroupId; +import org.onosproject.net.DeviceId; + +/** + * ONOS implementation of default group that is stored in the system. + */ +public class DefaultGroup extends DefaultGroupDescription + implements Group, StoredGroupEntry { + + private GroupState state; + private boolean isGroupStateAddedFirstTime; + private long life; + private long packets; + private long bytes; + private long referenceCount; + private GroupId id; + + /** + * Initializes default values. + * + * @param newId group id for new group + */ + private void initialize(GroupId newId) { + id = newId; + state = GroupState.PENDING_ADD; + life = 0; + packets = 0; + bytes = 0; + referenceCount = 0; + } + + /** + * Default group object constructor with the parameters. + * + * @param id group identifier + * @param groupDesc group description parameters + */ + public DefaultGroup(GroupId id, GroupDescription groupDesc) { + super(groupDesc); + initialize(id); + } + + /** + * Default group object constructor with the available information + * from data plane. + * + * @param id group identifier + * @param deviceId device identifier + * @param type type of the group + * @param buckets immutable list of group bucket + */ + public DefaultGroup(GroupId id, + DeviceId deviceId, + GroupDescription.Type type, + GroupBuckets buckets) { + super(deviceId, type, buckets); + initialize(id); + } + + /** + * Returns group identifier associated with a group object. + * + * @return GroupId Group Identifier + */ + @Override + public GroupId id() { + return this.id; + } + + /** + * Returns current state of a group object. + * + * @return GroupState Group State + */ + @Override + public GroupState state() { + return this.state; + } + + /** + * Returns the number of milliseconds this group has been alive. + * + * @return number of millis + */ + @Override + public long life() { + return this.life; + } + + /** + * Returns the number of packets processed by this group. + * + * @return number of packets + */ + @Override + public long packets() { + return this.packets; + } + + /** + * Returns the number of bytes processed by this group. + * + * @return number of bytes + */ + @Override + public long bytes() { + return this.bytes; + } + + /** + * Sets the new state for this entry. + * + * @param newState new group entry state. + */ + @Override + public void setState(Group.GroupState newState) { + this.state = newState; + } + + /** + * Sets how long this entry has been entered in the system. + * + * @param life epoch time + */ + @Override + public void setLife(long life) { + this.life = life; + } + + /** + * Sets number of packets processed by this group entry. + * + * @param packets a long value + */ + @Override + public void setPackets(long packets) { + this.packets = packets; + } + + /** + * Sets number of bytes processed by this group entry. + * + * @param bytes a long value + */ + @Override + public void setBytes(long bytes) { + this.bytes = bytes; + } + + @Override + public void setReferenceCount(long referenceCount) { + this.referenceCount = referenceCount; + } + + @Override + public long referenceCount() { + return referenceCount; + } + + /* + * The deviceId, type and buckets are used for hash. + * + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public int hashCode() { + return super.hashCode() + Objects.hash(id); + } + + /* + * The deviceId, groupId, type and buckets should be same. + * + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultGroup) { + DefaultGroup that = (DefaultGroup) obj; + return super.equals(obj) && + Objects.equals(id, that.id); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("description", super.toString()) + .add("groupid", id) + .add("state", state) + .toString(); + } + + @Override + public void setIsGroupStateAddedFirstTime(boolean isGroupStateAddedFirstTime) { + this.isGroupStateAddedFirstTime = isGroupStateAddedFirstTime; + } + + @Override + public boolean isGroupStateAddedFirstTime() { + return isGroupStateAddedFirstTime; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java new file mode 100644 index 00000000..6efd3e79 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java @@ -0,0 +1,252 @@ +/* + * 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.group; + +import org.onosproject.core.GroupId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.instructions.Instruction; + +import java.util.List; +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Group bucket implementation. A group bucket is collection of + * instructions that can be performed on a traffic flow. A select + * Group can have one or more Buckets where traffic will be + * processed by a single bucket in the group, based on device + * specific selection algorithm (e.g. hash on some fields of the + * incoming traffic flows or round robin) and hence can contains + * optional weight field to define the weights among the buckets + * in the group. A failover group bucket is associated with a + * specific port or group that controls its liveness. + */ +public final class DefaultGroupBucket implements GroupBucket, StoredGroupBucketEntry { + private final GroupDescription.Type type; + private final TrafficTreatment treatment; + private final short weight; + private final PortNumber watchPort; + private final GroupId watchGroup; + private long packets; + private long bytes; + + /** + * Group bucket constructor with the parameters. + * + * @param type group bucket type + * @param treatment traffic treatment associated with group bucket + * @param weight optional weight associated with group bucket + * @param watchPort port that determines the liveness of group bucket + * @param watchGroup group that determines the liveness of group bucket + */ + private DefaultGroupBucket(GroupDescription.Type type, + TrafficTreatment treatment, + short weight, + PortNumber watchPort, + GroupId watchGroup) { + this.type = type; + this.treatment = checkNotNull(treatment); + this.weight = weight; + this.watchPort = watchPort; + this.watchGroup = watchGroup; + } + + /** + * Creates indirect group bucket. + * + * @param treatment traffic treatment associated with group bucket + * @return indirect group bucket object + */ + public static GroupBucket createIndirectGroupBucket( + TrafficTreatment treatment) { + return new DefaultGroupBucket(GroupDescription.Type.INDIRECT, + treatment, + (short) -1, + null, + null); + } + + /** + * Creates select group bucket with weight as 1. + * + * @param treatment traffic treatment associated with group bucket + * @return select group bucket object + */ + public static GroupBucket createSelectGroupBucket( + TrafficTreatment treatment) { + return new DefaultGroupBucket(GroupDescription.Type.SELECT, + treatment, + (short) 1, + null, + null); + } + + /** + * Creates select group bucket with specified weight. + * + * @param treatment traffic treatment associated with group bucket + * @param weight weight associated with group bucket + * @return select group bucket object + */ + public static GroupBucket createSelectGroupBucket( + TrafficTreatment treatment, + short weight) { + if (weight == 0) { + return null; + } + + return new DefaultGroupBucket(GroupDescription.Type.SELECT, + treatment, + weight, + null, + null); + } + + /** + * Creates failover group bucket with watchport or watchgroup. + * + * @param treatment traffic treatment associated with group bucket + * @param watchPort port that determines the liveness of group bucket + * @param watchGroup group that determines the liveness of group bucket + * @return failover group bucket object + */ + public static GroupBucket createFailoverGroupBucket( + TrafficTreatment treatment, + PortNumber watchPort, + GroupId watchGroup) { + checkArgument(((watchPort != null) || (watchGroup != null))); + return new DefaultGroupBucket(GroupDescription.Type.FAILOVER, + treatment, + (short) -1, + watchPort, + watchGroup); + } + + @Override + public GroupDescription.Type type() { + return this.type; + } + + /** + * Returns list of Traffic instructions that are part of the bucket. + * + * @return TrafficTreatment Traffic instruction list + */ + @Override + public TrafficTreatment treatment() { + return treatment; + } + + /** + * Returns weight of select group bucket. + * + * @return short weight associated with a bucket + */ + @Override + public short weight() { + return weight; + } + + /** + * Returns port number used for liveness detection for a + * failover bucket. + * + * @return PortNumber port number used for liveness detection + */ + @Override + public PortNumber watchPort() { + return watchPort; + } + + /** + * Returns group identifier used for liveness detection for a + * failover bucket. + * + * @return GroupId group identifier to be used for liveness detection + */ + @Override + public GroupId watchGroup() { + return watchGroup; + } + + /* + * The type and treatment can change on a given bucket + * + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public int hashCode() { + return Objects.hash(type, treatment); + } + + /* + * The priority and statistics can change on a given treatment and selector + * + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultGroupBucket) { + DefaultGroupBucket that = (DefaultGroupBucket) obj; + List myInstructions = this.treatment.allInstructions(); + List theirInstructions = that.treatment.allInstructions(); + + return Objects.equals(type, that.type) && + myInstructions.containsAll(theirInstructions) && + theirInstructions.containsAll(myInstructions); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("type", type) + .add("treatment", treatment) + .add("packets", packets) + .add("bytes", bytes) + .toString(); + } + + @Override + public long packets() { + return packets; + } + + @Override + public long bytes() { + return bytes; + } + + @Override + public void setPackets(long packets) { + this.packets = packets; + } + + @Override + public void setBytes(long bytes) { + this.bytes = bytes; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupDescription.java new file mode 100644 index 00000000..1580d835 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupDescription.java @@ -0,0 +1,204 @@ +/* + * 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.group; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Objects; + +import org.onosproject.core.ApplicationId; +import org.onosproject.net.DeviceId; + +/** + * Default implementation of group description interface. + */ +public class DefaultGroupDescription implements GroupDescription { + private final GroupDescription.Type type; + private final GroupBuckets buckets; + private final GroupKey appCookie; + private final ApplicationId appId; + private final DeviceId deviceId; + private final Integer givenGroupId; + + /** + * Constructor to be used by north bound applications. + * NOTE: The caller of this subsystem MUST ensure the appCookie + * provided in this API is immutable. + * NOTE: The caller may choose to pass in 'null' for the groupId. This is + * the typical case, where the caller allows the group subsystem to choose + * the groupId in a globally unique way. If the caller passes in the groupId, + * the caller MUST ensure that the id is globally unique (not just unique + * per device). + * + * @param deviceId device identifier + * @param type type of the group + * @param buckets immutable list of group bucket + * @param appCookie immutable application cookie of type DefaultGroupKey + * to be associated with the group + * @param groupId group identifier + * @param appId application id + */ + public DefaultGroupDescription(DeviceId deviceId, + GroupDescription.Type type, + GroupBuckets buckets, + GroupKey appCookie, + Integer groupId, + ApplicationId appId) { + this.type = checkNotNull(type); + this.deviceId = checkNotNull(deviceId); + this.buckets = checkNotNull(buckets); + this.appCookie = appCookie; + this.givenGroupId = groupId; + this.appId = appId; + } + + /** + * Constructor to be used by group subsystem internal components. + * Creates group description object from another object of same type. + * + * @param groupDesc group description object + * + */ + public DefaultGroupDescription(GroupDescription groupDesc) { + this.type = groupDesc.type(); + this.deviceId = groupDesc.deviceId(); + this.buckets = groupDesc.buckets(); + this.appCookie = groupDesc.appCookie(); + this.appId = groupDesc.appId(); + this.givenGroupId = groupDesc.givenGroupId(); + } + + /** + * Constructor to be used by group subsystem internal components. + * Creates group description object from the information retrieved + * from data plane. + * + * @param deviceId device identifier + * @param type type of the group + * @param buckets immutable list of group bucket + * + */ + public DefaultGroupDescription(DeviceId deviceId, + GroupDescription.Type type, + GroupBuckets buckets) { + this(deviceId, type, buckets, null, null, null); + } + + /** + * Returns type of a group object. + * + * @return GroupType group type + */ + @Override + public GroupDescription.Type type() { + return this.type; + } + + /** + * Returns device identifier on which this group object is created. + * + * @return DeviceId device identifier + */ + @Override + public DeviceId deviceId() { + return this.deviceId; + } + + /** + * Returns application identifier that has created this group object. + * + * @return ApplicationId application identifier + */ + @Override + public ApplicationId appId() { + return this.appId; + } + + /** + * Returns application cookie associated with a group object. + * + * @return GroupKey application cookie + */ + @Override + public GroupKey appCookie() { + return this.appCookie; + } + + /** + * Returns group buckets of a group. + * + * @return GroupBuckets immutable list of group bucket + */ + @Override + public GroupBuckets buckets() { + return this.buckets; + } + + /** + * Returns groupId passed in by application. + * + * @return Integer group Id passed in by caller. May be null if caller passed + * in null during GroupDescription creation. + */ + @Override + public Integer givenGroupId() { + return this.givenGroupId; + } + + @Override + /* + * The deviceId, type and buckets are used for hash. + * + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public int hashCode() { + return Objects.hash(deviceId, type, buckets); + } + + @Override + /* + * The deviceId, type and buckets should be same. + * + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultGroupDescription) { + DefaultGroupDescription that = (DefaultGroupDescription) obj; + return Objects.equals(deviceId, that.deviceId) && + Objects.equals(type, that.type) && + Objects.equals(buckets, that.buckets); + + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("deviceId", deviceId) + .add("type", type) + .add("buckets", buckets) + .add("appId", appId) + .add("givenGroupId", givenGroupId) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupKey.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupKey.java new file mode 100644 index 00000000..7f00ae70 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/DefaultGroupKey.java @@ -0,0 +1,55 @@ +/* + * 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.group; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Arrays; + +/** + * Default implementation of group key interface. + */ +public class DefaultGroupKey implements GroupKey { + + private final byte[] key; + + public DefaultGroupKey(byte[] key) { + this.key = checkNotNull(key); + } + + @Override + public byte[] key() { + return key; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof DefaultGroupKey)) { + return false; + } + DefaultGroupKey that = (DefaultGroupKey) o; + return (Arrays.equals(this.key, that.key)); + } + + @Override + public int hashCode() { + return Arrays.hashCode(this.key); + } + +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/Group.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/Group.java new file mode 100644 index 00000000..54407752 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/Group.java @@ -0,0 +1,99 @@ +/* + * 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.group; + +import org.onosproject.core.GroupId; + +/** + * ONOS representation of group that is stored in the system. + */ +public interface Group extends GroupDescription { + /** + * State of the group object in ONOS. + */ + enum GroupState { + /** + * Group create request is queued as group AUDIT is in progress. + */ + WAITING_AUDIT_COMPLETE, + /** + * Group create request is processed by ONOS and not yet + * received the confirmation from data plane. + */ + PENDING_ADD, + /** + * Group is missing in data plane and retrying GROUP ADD request. + */ + PENDING_ADD_RETRY, + /** + * Group is created in the data plane. + */ + ADDED, + /** + * Group update request is processed by ONOS and not + * received the confirmation from data plane post which + * state moves to ADDED state. + */ + PENDING_UPDATE, + /** + * Group delete request is processed by ONOS and not + * received the confirmation from data plane. + */ + PENDING_DELETE + } + + /** + * Returns group identifier associated with a group object. + * + * @return GroupId Group Identifier + */ + GroupId id(); + + /** + * Returns current state of a group object. + * + * @return GroupState Group State + */ + GroupState state(); + + /** + * Returns the number of milliseconds this group has been alive. + * + * @return number of millis + */ + long life(); + + /** + * Returns the number of packets processed by this group. + * + * @return number of packets + */ + long packets(); + + /** + * Returns the number of bytes processed by this group. + * + * @return number of bytes + */ + long bytes(); + + /** + * Returns the number of flow rules or other groups reference this group. + * + * @return number of flow rules or other groups pointing to this group + */ + long referenceCount(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupBucket.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupBucket.java new file mode 100644 index 00000000..a503c154 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupBucket.java @@ -0,0 +1,80 @@ +/* + * 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.group; + +import org.onosproject.core.GroupId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.TrafficTreatment; + +/** + * Group Bucket definition. A default group Bucket is collection of + * Instructions that can be performed on a traffic flow. A failover + * group bucket is associated with a specific port or group that + * controls its liveness. A select group bucket contains optional + * weight field to define the weights among the buckets in the group. + */ +public interface GroupBucket { + /** + * Returns group type of the bucket. + * + * @return GroupType group type + */ + GroupDescription.Type type(); + + /** + * Returns list of Traffic instructions that are part of the bucket. + * + * @return TrafficTreatment traffic instruction list + */ + TrafficTreatment treatment(); + + /** + * Returns weight of select group bucket. + * + * @return short weight associated with a bucket + */ + short weight(); + + /** + * Returns port number used for liveness detection for a + * failover bucket. + * + * @return PortNumber port number used for liveness detection + */ + PortNumber watchPort(); + + /** + * Returns group identifier used for liveness detection for a + * failover bucket. + * + * @return GroupId group identifier to be used for liveness detection + */ + GroupId watchGroup(); + + /** + * Returns the number of packets processed by this group bucket. + * + * @return number of packets + */ + long packets(); + + /** + * Returns the number of bytes processed by this group bucket. + * + * @return number of bytes + */ + long bytes(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupBuckets.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupBuckets.java new file mode 100644 index 00000000..c0b5e5c6 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupBuckets.java @@ -0,0 +1,76 @@ +/* + * 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.group; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; + +import com.google.common.collect.ImmutableList; + +/** + * Immutable collection of group bucket. + */ +public final class GroupBuckets { + private final List buckets; + + /** + * Creates a immutable list of group bucket. + * + * @param buckets list of group bucket + */ + public GroupBuckets(List buckets) { + this.buckets = ImmutableList.copyOf(checkNotNull(buckets)); + } + + /** + * Returns immutable list of group buckets. + * + * @return list of group bucket + */ + public List buckets() { + return buckets; + } + + @Override + public int hashCode() { + int result = 17; + int combinedHash = 0; + for (GroupBucket bucket:buckets) { + combinedHash = combinedHash + bucket.hashCode(); + } + result = 31 * result + combinedHash; + + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof GroupBuckets) { + return (this.buckets.containsAll(((GroupBuckets) obj).buckets) && + ((GroupBuckets) obj).buckets.containsAll(this.buckets)); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("buckets", buckets.toString()) + .toString(); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupDescription.java new file mode 100644 index 00000000..671b9a54 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupDescription.java @@ -0,0 +1,91 @@ +/* + * 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.group; + +import org.onosproject.core.ApplicationId; +import org.onosproject.net.DeviceId; + +/** + * ONOS representation of group description that is used to create + * a group. It contains immutable properties of a ONOS group construct + * such as "type", "DeviceId", "appCookie", "appId" and "buckets" + */ +public interface GroupDescription { + /** + * Types of the group supported by ONOS. + */ + enum Type { + /** + * Load-balancing among different buckets in a group. + */ + SELECT, + /** + * Single Bucket Group. + */ + INDIRECT, + /** + * Multicast to all buckets in a group. + */ + ALL, + /** + * Uses the first live bucket in a group. + */ + FAILOVER + } + + /** + * Returns type of a group object. + * + * @return GroupType group type + */ + Type type(); + + /** + * Returns device identifier on which this group object is created. + * + * @return DeviceId device identifier + */ + DeviceId deviceId(); + + /** + * Returns application identifier that has created this group object. + * + * @return ApplicationId application identifier + */ + ApplicationId appId(); + + /** + * Returns application cookie associated with a group object. + * + * @return GroupKey application cookie + */ + GroupKey appCookie(); + + /** + * Returns groupId passed in by caller. + * + * @return Integer group id passed in by caller. May be null if caller + * passed in null to let groupService determin the group id. + */ + Integer givenGroupId(); + + /** + * Returns group buckets of a group. + * + * @return GroupBuckets immutable list of group bucket + */ + GroupBuckets buckets(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupEvent.java new file mode 100644 index 00000000..45fbb3ed --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupEvent.java @@ -0,0 +1,99 @@ +/* + * 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.group; + +import org.onosproject.event.AbstractEvent; + +/** + * Describes group events. + */ +public class GroupEvent extends AbstractEvent { + + /** + * Type of flow rule events. + */ + public enum Type { + /** + * Signifies that a new Group has been detected. + */ + GROUP_ADDED, + + /** + * Signifies that a Group has been removed. + */ + GROUP_REMOVED, + + /** + * Signifies that a Group has been updated. + */ + GROUP_UPDATED, + + /** + * Signifies that a request to create Group has failed. + */ + GROUP_ADD_FAILED, + + /** + * Signifies that a request to remove Group has failed. + */ + GROUP_REMOVE_FAILED, + + /** + * Signifies that a request to update Group has failed. + */ + GROUP_UPDATE_FAILED, + + // internal event between Manager <-> Store + + /* + * Signifies that a request to create Group has been added to the store. + */ + GROUP_ADD_REQUESTED, + /* + * Signifies that a request to update Group has been added to the store. + */ + GROUP_UPDATE_REQUESTED, + /* + * Signifies that a request to delete Group has been added to the store. + */ + GROUP_REMOVE_REQUESTED, + + + } + + /** + * Creates an event of a given type and for the specified Group and the + * current time. + * + * @param type Group event type + * @param group event subject + */ + public GroupEvent(Type type, Group group) { + super(type, group); + } + + /** + * Creates an event of a given type and for the specified Group and time. + * + * @param type Group event type + * @param group event subject + * @param time occurrence time + */ + public GroupEvent(Type type, Group group, long time) { + super(type, group, time); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupKey.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupKey.java new file mode 100644 index 00000000..a63bee27 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupKey.java @@ -0,0 +1,31 @@ +/* + * 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.group; + +/** + * Representation of generalized Key that would be used to store + * groups in < Key, Value > store. This key uses a generic + * byte array so that applications can associate their groups with + * any of their data by translating it into a byte array. + */ +public interface GroupKey { + /** + * Returns the byte representation of key. + * + * @return byte array + */ + byte[] key(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupListener.java new file mode 100644 index 00000000..349ce6a7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupListener.java @@ -0,0 +1,24 @@ +/* + * 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.group; + +import org.onosproject.event.EventListener; + +/** + * Entity capable of receiving Group related events. + */ +public interface GroupListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupOperation.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupOperation.java new file mode 100644 index 00000000..e4173b30 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupOperation.java @@ -0,0 +1,181 @@ +/* + * 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.group; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Objects; + +import org.onosproject.core.GroupId; + +/** + * Group operation definition to be used between core and provider + * layers of group subsystem. + * + */ +public final class GroupOperation { + private final Type opType; + private final GroupId groupId; + private final GroupDescription.Type groupType; + private final GroupBuckets buckets; + + public enum Type { + /** + * Create a group in a device with the specified parameters. + */ + ADD, + /** + * Modify a group in a device with the specified parameters. + */ + MODIFY, + /** + * Delete a specified group. + */ + DELETE + } + + /** + * Group operation constructor with the parameters. + * + * @param opType group operation type + * @param groupId group Identifier + * @param groupType type of the group + * @param buckets immutable list of group buckets to be part of group + */ + private GroupOperation(Type opType, + GroupId groupId, + GroupDescription.Type groupType, + GroupBuckets buckets) { + this.opType = checkNotNull(opType); + this.groupId = checkNotNull(groupId); + this.groupType = checkNotNull(groupType); + this.buckets = buckets; + } + + /** + * Creates ADD group operation object. + * + * @param groupId group Identifier + * @param groupType type of the group + * @param buckets immutable list of group buckets to be part of group + * @return add group operation object + */ + public static GroupOperation createAddGroupOperation(GroupId groupId, + GroupDescription.Type groupType, + GroupBuckets buckets) { + checkNotNull(buckets); + return new GroupOperation(Type.ADD, groupId, groupType, buckets); + } + + /** + * Creates MODIFY group operation object. + * + * @param groupId group Identifier + * @param groupType type of the group + * @param buckets immutable list of group buckets to be part of group + * @return modify group operation object + */ + public static GroupOperation createModifyGroupOperation(GroupId groupId, + GroupDescription.Type groupType, + GroupBuckets buckets) { + checkNotNull(buckets); + return new GroupOperation(Type.MODIFY, groupId, groupType, buckets); + + } + + /** + * Creates DELETE group operation object. + * + * @param groupId group Identifier + * @param groupType type of the group + * @return delete group operation object + */ + public static GroupOperation createDeleteGroupOperation(GroupId groupId, + GroupDescription.Type groupType) { + return new GroupOperation(Type.DELETE, groupId, groupType, null); + + } + + /** + * Returns group operation type. + * + * @return GroupOpType group operation type + */ + public Type opType() { + return this.opType; + } + + /** + * Returns group identifier attribute of the operation. + * + * @return GroupId group identifier + */ + public GroupId groupId() { + return this.groupId; + } + + /** + * Returns group type attribute of the operation. + * + * @return GroupType group type + */ + public GroupDescription.Type groupType() { + return this.groupType; + } + + /** + * Returns group buckets associated with the operation. + * + * @return GroupBuckets group buckets + */ + public GroupBuckets buckets() { + return this.buckets; + } + + @Override + /* + * The deviceId, type and buckets are used for hash. + * + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public int hashCode() { + return (buckets != null) ? Objects.hash(groupId, opType, buckets) : + Objects.hash(groupId, opType); + } + + @Override + /* + * The deviceId, type and buckets should be same. + * + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof GroupOperation) { + GroupOperation that = (GroupOperation) obj; + return Objects.equals(groupId, that.groupId) && + Objects.equals(groupType, that.groupType) && + Objects.equals(opType, that.opType) && + Objects.equals(buckets, that.buckets); + + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupOperations.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupOperations.java new file mode 100644 index 00000000..bc03628d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupOperations.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.net.group; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; + +import com.google.common.collect.ImmutableList; + +/** + * Immutable collection of group operation to be used between + * core and provider layers of group subsystem. + * + */ +public final class GroupOperations { + private final List operations; + + /** + * Creates a immutable list of group operation. + * + * @param operations list of group operation + */ + public GroupOperations(List operations) { + this.operations = ImmutableList.copyOf(checkNotNull(operations)); + } + + /** + * Returns immutable list of group operation. + * + * @return list of group operation + */ + public List operations() { + return operations; + } + +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupProvider.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupProvider.java new file mode 100644 index 00000000..6757e669 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupProvider.java @@ -0,0 +1,37 @@ +/* + * 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.group; + +import org.onosproject.net.DeviceId; +import org.onosproject.net.provider.Provider; + +/** + * Abstraction of group provider. + */ +public interface GroupProvider extends Provider { + + /** + * Performs a batch of group operation in the specified device with the + * specified parameters. + * + * @param deviceId device identifier on which the batch of group + * operations to be executed + * @param groupOps immutable list of group operation + */ + void performGroupOperation(DeviceId deviceId, + GroupOperations groupOps); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupProviderRegistry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupProviderRegistry.java new file mode 100644 index 00000000..d45789db --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupProviderRegistry.java @@ -0,0 +1,25 @@ +/* + * 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.group; + +import org.onosproject.net.provider.ProviderRegistry; + +/** + * Abstraction for a group provider registry. + */ +public interface GroupProviderRegistry + extends ProviderRegistry { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupProviderService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupProviderService.java new file mode 100644 index 00000000..076de498 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupProviderService.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.group; + +import java.util.Collection; + +import org.onosproject.net.DeviceId; +import org.onosproject.net.provider.ProviderService; + +/** + * Service through which Group providers can inject information into + * the core. + */ +public interface GroupProviderService extends ProviderService { + + /** + * Notifies core if any failure from data plane during group operations. + * + * @param deviceId the device ID + * @param operation offended group operation + */ + void groupOperationFailed(DeviceId deviceId, GroupOperation operation); + + /** + * Pushes the collection of group detected in the data plane along + * with statistics. + * + * @param deviceId device identifier + * @param groupEntries collection of group entries as seen in data plane + */ + void pushGroupMetrics(DeviceId deviceId, + Collection groupEntries); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupService.java new file mode 100644 index 00000000..4163248f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupService.java @@ -0,0 +1,139 @@ +/* + * 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.group; + +import org.onosproject.core.ApplicationId; +import org.onosproject.event.ListenerService; +import org.onosproject.net.DeviceId; + +/** + * Service for create/update/delete "group" in the devices. + * Flow entries can point to a "group" defined in the devices that enables + * to represent additional methods of forwarding like load-balancing or + * failover among different group of ports or multicast to all ports + * specified in a group. + * "group" can also be used for grouping common actions of different flows, + * so that in some scenarios only one group entry required to be modified + * for all the referencing flow entries instead of modifying all of them. + * + * This implements semantics of a distributed authoritative group store + * where the master copy of the groups lies with the controller and + * the devices hold only the 'cached' copy. + */ +public interface GroupService + extends ListenerService { + + /** + * Creates a group in the specified device with the provided buckets. + * This API provides an option for application to associate a cookie + * while creating a group, so that applications can look-up the + * groups based on the cookies. These Groups will be retained by + * the core system and re-applied if any groups found missing in the + * device when it reconnects. This API would immediately return after + * submitting the request locally or to a remote Master controller + * instance. As a response to this API invocation, GROUP_ADDED or + * GROUP_ADD_FAILED notifications would be provided along with cookie + * depending on the result of the operation on the device in the + * data plane. The caller may also use "getGroup" API to get the + * Group object created as part of this request. + * + * @param groupDesc group creation parameters + * + */ + void addGroup(GroupDescription groupDesc); + + /** + * Returns a group object associated to an application cookie. + * + * NOTE1: The presence of group object in the system does not + * guarantee that the "group" is actually created in device. + * GROUP_ADDED notification would confirm the creation of + * this group in data plane. + * + * @param deviceId device identifier + * @param appCookie application cookie to be used for lookup + * @return group associated with the application cookie or + * NULL if Group is not found for the provided cookie + */ + Group getGroup(DeviceId deviceId, GroupKey appCookie); + + /** + * Appends buckets to existing group. The caller can optionally + * associate a new cookie during this updation. GROUP_UPDATED or + * GROUP_UPDATE_FAILED notifications would be provided along with + * cookie depending on the result of the operation on the device. + * + * @param deviceId device identifier + * @param oldCookie cookie to be used to retrieve the existing group + * @param buckets immutable list of group bucket to be added + * @param newCookie immutable cookie to be used post update operation + * @param appId Application Id + */ + void addBucketsToGroup(DeviceId deviceId, + GroupKey oldCookie, + GroupBuckets buckets, + GroupKey newCookie, + ApplicationId appId); + + /** + * Removes buckets from existing group. The caller can optionally + * associate a new cookie during this updation. GROUP_UPDATED or + * GROUP_UPDATE_FAILED notifications would be provided along with + * cookie depending on the result of the operation on the device. + * + * @param deviceId device identifier + * @param oldCookie cookie to be used to retrieve the existing group + * @param buckets immutable list of group bucket to be removed + * @param newCookie immutable cookie to be used post update operation + * @param appId Application Id + */ + void removeBucketsFromGroup(DeviceId deviceId, + GroupKey oldCookie, + GroupBuckets buckets, + GroupKey newCookie, + ApplicationId appId); + + /** + * Deletes a group associated to an application cookie. + * GROUP_DELETED or GROUP_DELETE_FAILED notifications would be + * provided along with cookie depending on the result of the + * operation on the device. + * + * @param deviceId device identifier + * @param appCookie application cookie to be used for lookup + * @param appId Application Id + */ + void removeGroup(DeviceId deviceId, GroupKey appCookie, ApplicationId appId); + + /** + * Retrieves all groups created by an application in the specified device + * as seen by current controller instance. + * + * @param deviceId device identifier + * @param appId application id + * @return collection of immutable group objects created by the application + */ + Iterable getGroups(DeviceId deviceId, ApplicationId appId); + + /** + * Returns all groups associated with the given device. + * + * @param deviceId device ID to get groups for + * @return iterable of device's groups + */ + Iterable getGroups(DeviceId deviceId); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupStore.java new file mode 100644 index 00000000..8b6df5d9 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupStore.java @@ -0,0 +1,175 @@ +/* + * 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.group; + +import java.util.Collection; + +import org.onosproject.core.GroupId; +import org.onosproject.net.DeviceId; +import org.onosproject.store.Store; + +/** + * Manages inventory of groups per device; not intended for direct use. + */ +public interface GroupStore extends Store { + + enum UpdateType { + /** + * Modify existing group entry by adding provided information. + */ + ADD, + /** + * Modify existing group by removing provided information from it. + */ + REMOVE + } + + /** + * Returns the number of groups for the specified device in the store. + * + * @param deviceId the device ID + * @return number of groups for the specified device + */ + int getGroupCount(DeviceId deviceId); + + /** + * Returns the groups associated with a device. + * + * @param deviceId the device ID + * @return the group entries + */ + Iterable getGroups(DeviceId deviceId); + + /** + * Returns the stored group entry. + * + * @param deviceId the device ID + * @param appCookie the group key + * @return a group associated with the key + */ + Group getGroup(DeviceId deviceId, GroupKey appCookie); + + /** + * Returns the stored group entry for an id. + * + * @param deviceId the device ID + * @param groupId the group identifier + * @return a group associated with the key + */ + Group getGroup(DeviceId deviceId, GroupId groupId); + + /** + * Stores a new group entry using the information from group description. + * + * @param groupDesc group description to be used to store group entry + */ + void storeGroupDescription(GroupDescription groupDesc); + + /** + * Updates the existing group entry with the information + * from group description. + * + * @param deviceId the device ID + * @param oldAppCookie the current group key + * @param type update type + * @param newBuckets group buckets for updates + * @param newAppCookie optional new group key + */ + void updateGroupDescription(DeviceId deviceId, + GroupKey oldAppCookie, + UpdateType type, + GroupBuckets newBuckets, + GroupKey newAppCookie); + + /** + * Triggers deleting the existing group entry. + * + * @param deviceId the device ID + * @param appCookie the group key + */ + void deleteGroupDescription(DeviceId deviceId, + GroupKey appCookie); + + /** + * Stores a new group entry, or updates an existing entry. + * + * @param group group entry + */ + void addOrUpdateGroupEntry(Group group); + + /** + * Removes the group entry from store. + * + * @param group group entry + */ + void removeGroupEntry(Group group); + + /** + * A group entry that is present in switch but not in the store. + * + * @param group group entry + */ + void addOrUpdateExtraneousGroupEntry(Group group); + + /** + * Remove the group entry from extraneous database. + * + * @param group group entry + */ + void removeExtraneousGroupEntry(Group group); + + /** + * Returns the extraneous groups associated with a device. + * + * @param deviceId the device ID + * + * @return the extraneous group entries + */ + Iterable getExtraneousGroups(DeviceId deviceId); + + /** + * Indicates the first group audit is completed. + * + * @param deviceId the device ID + * @param completed initial audit status + */ + void deviceInitialAuditCompleted(DeviceId deviceId, boolean completed); + + /** + * Retrieves the initial group audit status for a device. + * + * @param deviceId the device ID + * + * @return initial group audit status + */ + boolean deviceInitialAuditStatus(DeviceId deviceId); + + /** + * Indicates the group operations failed. + * + * @param deviceId the device ID + * @param operation the group operation failed + */ + void groupOperationFailed(DeviceId deviceId, GroupOperation operation); + + /** + * Submits the group metrics to store for a given device ID. + * + * @param deviceId the device ID + * @param groupEntries the group entries as received from southbound + */ + void pushGroupMetrics(DeviceId deviceId, Collection groupEntries); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupStoreDelegate.java new file mode 100644 index 00000000..308ebb1c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/GroupStoreDelegate.java @@ -0,0 +1,24 @@ +/* + * 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.group; + +import org.onosproject.store.StoreDelegate; + +/** + * Group store delegate abstraction. + */ +public interface GroupStoreDelegate extends StoreDelegate { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/StoredGroupBucketEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/StoredGroupBucketEntry.java new file mode 100644 index 00000000..131875b3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/StoredGroupBucketEntry.java @@ -0,0 +1,37 @@ +/* + * 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.group; + +/** + * Generic group bucket entry representation that is stored in a + * group object. A group bucket entry provides additional info of + * group bucket like statistics...etc + */ +public interface StoredGroupBucketEntry extends GroupBucket { + /** + * Sets number of packets processed by this group bucket entry. + * + * @param packets a long value + */ + void setPackets(long packets); + + /** + * Sets number of bytes processed by this group bucket entry. + * + * @param bytes a long value + */ + void setBytes(long bytes); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/StoredGroupEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/StoredGroupEntry.java new file mode 100644 index 00000000..47d36122 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/StoredGroupEntry.java @@ -0,0 +1,75 @@ +/* + * 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.group; + +/** + * Interface that defines set methods for a group entry + * that is stored in the system. + */ +public interface StoredGroupEntry extends Group { + + /** + * Sets the new state for this entry. + * + * @param newState new group entry state. + */ + void setState(Group.GroupState newState); + + /** + * Sets if group has transitioned to ADDED state for the first time. + * This is to differentiate state transitions "from PENDING_ADD to ADDED" + * and "from PENDING_UPDATE to ADDED". For internal use only. + * + * @param isGroupAddedFirstTime true if group moves to ADDED state + * for the first time. + */ + void setIsGroupStateAddedFirstTime(boolean isGroupAddedFirstTime); + + /** + * Returns the isGroupStateAddedFirstTime value. For internal use only. + * + * @return isGroupStateAddedFirstTime value + */ + boolean isGroupStateAddedFirstTime(); + + /** + * Sets how long this entry has been entered in the system. + * + * @param life epoch time + */ + void setLife(long life); + + /** + * Sets number of packets processed by this group entry. + * + * @param packets a long value + */ + void setPackets(long packets); + + /** + * Sets number of bytes processed by this group entry. + * + * @param bytes a long value + */ + void setBytes(long bytes); + + /** + * Sets number of flow rules or groups referencing this group entry. + * + * @param referenceCount reference count + */ + void setReferenceCount(long referenceCount); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/package-info.java new file mode 100644 index 00000000..26528c48 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/group/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. + */ + +/** + * Abstractions for interacting with device port groups. + */ +package org.onosproject.net.group; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/DefaultHostDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/DefaultHostDescription.java new file mode 100644 index 00000000..1f05197a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/DefaultHostDescription.java @@ -0,0 +1,122 @@ +/* + * Copyright 2014 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.host; + +import java.util.Collections; +import java.util.Set; + +import org.onosproject.net.AbstractDescription; +import org.onosproject.net.HostLocation; +import org.onosproject.net.SparseAnnotations; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; + +import com.google.common.collect.ImmutableSet; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Default implementation of an immutable host description. + */ +public class DefaultHostDescription extends AbstractDescription + implements HostDescription { + + private final MacAddress mac; + private final VlanId vlan; + private final HostLocation location; + private final Set ip; + + /** + * Creates a host description using the supplied information. + * + * @param mac host MAC address + * @param vlan host VLAN identifier + * @param location host location + * @param annotations optional key/value annotations map + */ + public DefaultHostDescription(MacAddress mac, VlanId vlan, + HostLocation location, + SparseAnnotations... annotations) { + this(mac, vlan, location, Collections.emptySet(), + annotations); + } + + /** + * Creates a host description using the supplied information. + * + * @param mac host MAC address + * @param vlan host VLAN identifier + * @param location host location + * @param ip host IP address + * @param annotations optional key/value annotations map + */ + public DefaultHostDescription(MacAddress mac, VlanId vlan, + HostLocation location, IpAddress ip, + SparseAnnotations... annotations) { + this(mac, vlan, location, ImmutableSet.of(ip), annotations); + } + + /** + * Creates a host description using the supplied information. + * + * @param mac host MAC address + * @param vlan host VLAN identifier + * @param location host location + * @param ip host IP addresses + * @param annotations optional key/value annotations map + */ + public DefaultHostDescription(MacAddress mac, VlanId vlan, + HostLocation location, Set ip, + SparseAnnotations... annotations) { + super(annotations); + this.mac = mac; + this.vlan = vlan; + this.location = location; + this.ip = ImmutableSet.copyOf(ip); + } + + @Override + public MacAddress hwAddress() { + return mac; + } + + @Override + public VlanId vlan() { + return vlan; + } + + @Override + public HostLocation location() { + return location; + } + + @Override + public Set ipAddress() { + return ip; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("mac", mac) + .add("vlan", vlan) + .add("location", location) + .add("ipAddress", ip) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostAdminService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostAdminService.java new file mode 100644 index 00000000..d620fedb --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostAdminService.java @@ -0,0 +1,66 @@ +/* + * Copyright 2014-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.host; + +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.HostId; + +/** + * Service for administering the inventory of end-station hosts. + */ +public interface HostAdminService extends HostService { + + /** + * Removes the end-station host with the specified identifier. + * + * @param hostId host identifier + */ + void removeHost(HostId hostId); + + /** + * Binds IP and MAC addresses to the given connection point. + *

+ * The addresses are added to the set of addresses already bound to the + * connection point. + * + * @param addresses address object containing addresses to add and the port + * to add them to + * @deprecated in Drake release: address info now stored in InterfaceService + */ + @Deprecated + void bindAddressesToPort(PortAddresses addresses); + + /** + * Removes the addresses contained in the given PortAddresses object from + * the set of addresses bound to the port. + * + * @param portAddresses set of addresses to remove and port to remove them + * from + * @deprecated in Drake release: address info now stored in InterfaceService + */ + @Deprecated + void unbindAddressesFromPort(PortAddresses portAddresses); + + /** + * Removes all address information for the given connection point. + * + * @param connectPoint the connection point to remove address information + * @deprecated in Drake release: address info now stored in InterfaceService + */ + @Deprecated + void clearAddresses(ConnectPoint connectPoint); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostDescription.java new file mode 100644 index 00000000..14c6f7ad --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostDescription.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014 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.host; + +import java.util.Set; + +import org.onosproject.net.Description; +import org.onosproject.net.HostLocation; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; + +/** + * Information describing host and its location. + */ +public interface HostDescription extends Description { + + /** + * Returns the MAC address associated with this host (NIC). + * + * @return the MAC address of this host + */ + MacAddress hwAddress(); + + /** + * Returns the VLAN associated with this host. + * + * @return the VLAN ID value + */ + VlanId vlan(); + + /** + * Returns the location of the host on the network edge. + * + * @return the network location + */ + HostLocation location(); + + /** + * Returns the IP address associated with this host's MAC. + * + * @return host IP address + */ + Set ipAddress(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostEvent.java new file mode 100644 index 00000000..98329df0 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostEvent.java @@ -0,0 +1,73 @@ +/* + * Copyright 2014 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.host; + +import org.onosproject.event.AbstractEvent; +import org.onosproject.net.Host; + +/** + * Describes end-station host event. + */ +public class HostEvent extends AbstractEvent { + + /** + * Type of host events. + */ + public enum Type { + /** + * Signifies that a new host has been detected. + */ + HOST_ADDED, + + /** + * Signifies that a host has been removed. + */ + HOST_REMOVED, + + /** + * Signifies that host data changed, e.g. IP address + */ + HOST_UPDATED, + + /** + * Signifies that a host location has changed. + */ + HOST_MOVED + } + + /** + * Creates an event of a given type and for the specified host and the + * current time. + * + * @param type host event type + * @param host event host subject + */ + public HostEvent(Type type, Host host) { + super(type, host); + } + + /** + * Creates an event of a given type and for the specified host and time. + * + * @param type host event type + * @param host event host subject + * @param time occurrence time + */ + public HostEvent(Type type, Host host, long time) { + super(type, host, time); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostListener.java new file mode 100644 index 00000000..2eef7592 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostListener.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.host; + +import org.onosproject.event.EventListener; + +/** + * Entity capable of receiving end-station host related events. + */ +public interface HostListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProvider.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProvider.java new file mode 100644 index 00000000..0270996b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProvider.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 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.host; + +import org.onosproject.net.Host; +import org.onosproject.net.provider.Provider; + +/** + * Provider of information about hosts and their location on the network. + */ +public interface HostProvider extends Provider { + + /** + * Triggers an asynchronous probe of the specified host, intended to + * determine whether the host is present or not. An indirect result of this + * should be invocation of {@link org.onosproject.net.host.HostProviderService#hostDetected} + * or {@link org.onosproject.net.host.HostProviderService#hostVanished} + * at some later point in time. + * + * @param host host to probe + */ + void triggerProbe(Host host); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderRegistry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderRegistry.java new file mode 100644 index 00000000..8ab600c2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderRegistry.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 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.host; + +import org.onosproject.net.provider.ProviderRegistry; + +/** + * Abstraction of a host provider registry. + */ +public interface HostProviderRegistry + extends ProviderRegistry { +} 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 new file mode 100644 index 00000000..8678a297 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostProviderService.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014 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.host; + +import org.onosproject.net.HostId; +import org.onosproject.net.provider.ProviderService; + +/** + * Means of conveying host information to the core. + */ +public interface HostProviderService extends ProviderService { + + /** + * Notifies the core when a host has been detected on a network along with + * information that identifies the host location. + * + * @param hostId id of the host that been detected + * @param hostDescription description of host and its location + */ + void hostDetected(HostId hostId, HostDescription hostDescription); + + /** + * Notifies the core when a host is no longer detected on a network. + * + * @param hostId id of the host that vanished + */ + void hostVanished(HostId hostId); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostService.java new file mode 100644 index 00000000..be114f05 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostService.java @@ -0,0 +1,146 @@ +/* + * Copyright 2014 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.host; + +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; +import org.onosproject.event.ListenerService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Host; +import org.onosproject.net.HostId; + +import java.util.Set; + +/** + * Service for interacting with the inventory of end-station hosts. + */ +public interface HostService + extends ListenerService { + + /** + * Returns the number of end-station hosts known to the system. + * + * @return number of end-station hosts + */ + int getHostCount(); + + /** + * Returns a collection of all end-station hosts. + * + * @return collection of hosts + */ + Iterable getHosts(); + + /** + * Returns the host with the specified identifier. + * + * @param hostId host identifier + * @return host or null if one with the given identifier is not known + */ + Host getHost(HostId hostId); + + /** + * Returns the set of hosts that belong to the specified VLAN. + * + * @param vlanId vlan identifier + * @return set of hosts in the given vlan id + */ + Set getHostsByVlan(VlanId vlanId); + + /** + * Returns the set of hosts that have the specified MAC address. + * + * @param mac mac address + * @return set of hosts with the given mac + */ + Set getHostsByMac(MacAddress mac); + + /** + * Returns the set of hosts that have the specified IP address. + * + * @param ip ip address + * @return set of hosts with the given IP + */ + Set getHostsByIp(IpAddress ip); + + // TODO: consider adding Host getHostByIp(IpAddress ip, VlanId vlan); + + /** + * Returns the set of hosts whose most recent location is the specified + * connection point. + * + * @param connectPoint connection point + * @return set of hosts connected to the connection point + */ + Set getConnectedHosts(ConnectPoint connectPoint); + + /** + * Returns the set of hosts whose most recent location is the specified + * infrastructure device. + * + * @param deviceId device identifier + * @return set of hosts connected to the device + */ + Set getConnectedHosts(DeviceId deviceId); + + /** + * Requests the host service to monitor hosts with the given IP address and + * notify listeners of changes. + * + * @param ip IP address of the host to monitor + */ + void startMonitoringIp(IpAddress ip); + + /** + * Stops the host service from monitoring an IP address. + * + * @param ip IP address to stop monitoring + */ + // TODO clients can cancel other client's requests + void stopMonitoringIp(IpAddress ip); + + /** + * Requests the host service to resolve the MAC address for the given IP + * address. This will trigger a notification to the host listeners if the MAC + * address is found. + * + * @param ip IP address to find the MAC address for + */ + void requestMac(IpAddress ip); + + /** + * Returns the addresses information for all connection points. + * + * @return the set of address bindings for all connection points + * @deprecated in Drake release: use InterfaceService instead + */ + @Deprecated + Set getAddressBindings(); + + /** + * Retrieves the addresses that have been bound to the given connection + * point. + * + * @param connectPoint the connection point to retrieve address bindings for + * @return addresses bound to the port + * @deprecated in Drake release: use InterfaceService instead + */ + @Deprecated + Set getAddressBindingsForPort(ConnectPoint connectPoint); + +} 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 new file mode 100644 index 00000000..ca11a942 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStore.java @@ -0,0 +1,167 @@ +/* + * Copyright 2014 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.host; + +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Host; +import org.onosproject.net.HostId; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.store.Store; + +import java.util.Set; + +/** + * Manages inventory of end-station hosts; not intended for direct use. + */ +public interface HostStore extends Store { + + /** + * Creates a new host or updates the existing one based on the specified + * description. + * + * @param providerId provider identification + * @param hostId host identification + * @param hostDescription host description data + * @return appropriate event or null if no change resulted + */ + HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId, + HostDescription hostDescription); + + // FIXME: API to remove only IpAddress is missing + /** + * Removes the specified host from the inventory. + * + * @param hostId host identification + * @return remove event or null if host was not found + */ + HostEvent removeHost(HostId hostId); + + /** + * Returns the number of hosts in the store. + * + * @return host count + */ + int getHostCount(); + + /** + * Returns a collection of all hosts in the store. + * + * @return iterable collection of all hosts + */ + Iterable getHosts(); + + /** + * Returns the host with the specified identifer. + * + * @param hostId host identification + * @return host or null if not found + */ + Host getHost(HostId hostId); + + /** + * Returns the set of all hosts within the specified VLAN. + * + * @param vlanId vlan id + * @return set of hosts in the vlan + */ + Set getHosts(VlanId vlanId); + + /** + * Returns the set of hosts with the specified MAC address. + * + * @param mac mac address + * @return set of hosts with the given mac + */ + Set getHosts(MacAddress mac); + + /** + * Returns the set of hosts with the specified IP address. + * + * @param ip ip address + * @return set of hosts with the given IP + */ + Set getHosts(IpAddress ip); + + /** + * Returns the set of hosts whose location falls on the given connection point. + * + * @param connectPoint connection point + * @return set of hosts + */ + Set getConnectedHosts(ConnectPoint connectPoint); + + /** + * Returns the set of hosts whose location falls on the given device. + * + * @param deviceId infrastructure device identifier + * @return set of hosts + */ + Set getConnectedHosts(DeviceId deviceId); + + /** + * Updates the address information for a given port. The given address + * information is added to any previously held information for the port. + * + * @param addresses the port and address information + * @deprecated in Drake release: address info now stored in InterfaceService + */ + @Deprecated + void updateAddressBindings(PortAddresses addresses); + + /** + * Removes the given addresses from the set of address information held for + * a port. + * + * @param addresses the port and address information + * @deprecated in Drake release: address info now stored in InterfaceService + */ + @Deprecated + void removeAddressBindings(PortAddresses addresses); + + /** + * Removes any previously stored address information for a given connection + * point. + * + * @param connectPoint the connection point + * @deprecated in Drake release: address info now stored in InterfaceService + */ + @Deprecated + void clearAddressBindings(ConnectPoint connectPoint); + + /** + * Returns the address bindings stored for all connection points. + * + * @return the set of address bindings + * @deprecated in Drake release: address info now stored in InterfaceService + */ + @Deprecated + Set getAddressBindings(); + + /** + * Returns the address bindings for a particular connection point. + * + * @param connectPoint the connection point to return address information + * for + * @return address information for the connection point + * @deprecated in Drake release: address info now stored in InterfaceService + */ + @Deprecated + Set getAddressBindingsForPort(ConnectPoint connectPoint); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStoreDelegate.java new file mode 100644 index 00000000..efc84232 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/HostStoreDelegate.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.host; + +import org.onosproject.store.StoreDelegate; + +/** + * Infrastructure link store delegate abstraction. + */ +public interface HostStoreDelegate extends StoreDelegate { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/InterfaceIpAddress.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/InterfaceIpAddress.java new file mode 100644 index 00000000..2f53df50 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/InterfaceIpAddress.java @@ -0,0 +1,192 @@ +/* + * Copyright 2014 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.host; + +import org.onlab.packet.IpAddress; +import org.onlab.packet.IpPrefix; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a single IP address information on an interface. + * + * TODO: + * - Add computation for the default broadcast address if it is not + * specified + * - Add explicit checks that each IP address or prefix belong to the + * same IP version: IPv4/IPv6. + * - Inside the copy constructor we should use copy constructors for each + * field + */ +public class InterfaceIpAddress { + private final IpAddress ipAddress; + private final IpPrefix subnetAddress; + private final IpAddress broadcastAddress; + private final IpAddress peerAddress; + + /** + * Copy constructor. + * + * @param other the object to copy from + */ + public InterfaceIpAddress(InterfaceIpAddress other) { + // TODO: we should use copy constructors for each field + this.ipAddress = other.ipAddress; + this.subnetAddress = other.subnetAddress; + this.broadcastAddress = other.broadcastAddress; + this.peerAddress = other.peerAddress; + } + + /** + * Constructor for a given IP address and a subnet address. + * + * @param ipAddress the IP address + * @param subnetAddress the IP subnet address + */ + public InterfaceIpAddress(IpAddress ipAddress, IpPrefix subnetAddress) { + this.ipAddress = checkNotNull(ipAddress); + this.subnetAddress = checkNotNull(subnetAddress); + // TODO: Recompute the default broadcast address from the subnet + // address + this.broadcastAddress = null; + this.peerAddress = null; + } + + /** + * Constructor for a given IP address and a subnet address. + * + * @param ipAddress the IP address + * @param subnetAddress the IP subnet address + * @param broadcastAddress the IP broadcast address. It can be used + * to specify non-default broadcast address + */ + public InterfaceIpAddress(IpAddress ipAddress, IpPrefix subnetAddress, + IpAddress broadcastAddress) { + this.ipAddress = checkNotNull(ipAddress); + this.subnetAddress = checkNotNull(subnetAddress); + this.broadcastAddress = broadcastAddress; + this.peerAddress = null; + } + + /** + * Constructor for a given IP address and a subnet address. + * + * @param ipAddress the IP address + * @param subnetAddress the IP subnet address + * @param broadcastAddress the IP broadcast address. It can be used + * to specify non-default broadcast address. It should be null for + * point-to-point interfaces with a peer address + * @param peerAddress the peer IP address for point-to-point interfaces + */ + public InterfaceIpAddress(IpAddress ipAddress, IpPrefix subnetAddress, + IpAddress broadcastAddress, + IpAddress peerAddress) { + this.ipAddress = checkNotNull(ipAddress); + this.subnetAddress = checkNotNull(subnetAddress); + this.broadcastAddress = broadcastAddress; + this.peerAddress = peerAddress; + } + + /** + * Gets the IP address. + * + * @return the IP address + */ + public IpAddress ipAddress() { + return ipAddress; + } + + /** + * Gets the IP subnet address. + * + * @return the IP subnet address + */ + public IpPrefix subnetAddress() { + return subnetAddress; + } + + /** + * Gets the subnet IP broadcast address. + * + * @return the subnet IP broadcast address + */ + public IpAddress broadcastAddress() { + return broadcastAddress; + } + + /** + * Gets the IP point-to-point interface peer address. + * + * @return the IP point-to-point interface peer address + */ + public IpAddress peerAddress() { + return peerAddress; + } + + /** + * Converts a CIDR string literal to an interface IP address. + * E.g. 10.0.0.1/24 + * + * @param value an IP address value in string form + * @return an interface IP address + * @throws IllegalArgumentException if the argument is invalid + */ + public static InterfaceIpAddress valueOf(String value) { + String[] splits = value.split("/"); + checkArgument(splits.length == 2, "Invalid IP address and prefix length format"); + + // NOTE: IpPrefix will mask-out the bits after the prefix length. + IpPrefix subnet = IpPrefix.valueOf(value); + IpAddress addr = IpAddress.valueOf(splits[0]); + return new InterfaceIpAddress(addr, subnet); + } + + @Override + public boolean equals(Object other) { + if (other == this) { + return true; + } + if (!(other instanceof InterfaceIpAddress)) { + return false; + } + InterfaceIpAddress otherAddr = (InterfaceIpAddress) other; + + return Objects.equals(this.ipAddress, otherAddr.ipAddress) + && Objects.equals(this.subnetAddress, otherAddr.subnetAddress) + && Objects.equals(this.broadcastAddress, + otherAddr.broadcastAddress) + && Objects.equals(this.peerAddress, otherAddr.peerAddress); + } + + @Override + public int hashCode() { + return Objects.hash(ipAddress, subnetAddress, broadcastAddress, + peerAddress); + } + + @Override + public String toString() { + /*return toStringHelper(this).add("ipAddress", ipAddress) + .add("subnetAddress", subnetAddress) + .add("broadcastAddress", broadcastAddress) + .add("peerAddress", peerAddress) + .omitNullValues().toString();*/ + return ipAddress.toString() + "/" + subnetAddress.prefixLength(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/PortAddresses.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/PortAddresses.java new file mode 100644 index 00000000..74f22ae9 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/PortAddresses.java @@ -0,0 +1,127 @@ +/* + * Copyright 2014-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.host; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; +import org.onosproject.net.ConnectPoint; + +import com.google.common.base.MoreObjects; + +/** + * Represents address information bound to a port. + */ +public final class PortAddresses { + + private final ConnectPoint connectPoint; + private final Set ipAddresses; + private final MacAddress macAddress; + private final VlanId vlan; + + /** + * Constructs a PortAddresses object for the given connection point, with a + * set of IP addresses and a MAC address. Both address parameters are + * optional and can be set to null. + * + * @param connectPoint the connection point these addresses are for + * @param ipAddresses a set of interface IP addresses + * @param mac a MAC address + * @param vlan a VLAN ID + */ + public PortAddresses(ConnectPoint connectPoint, + Set ipAddresses, MacAddress mac, VlanId vlan) { + this.connectPoint = connectPoint; + this.ipAddresses = (ipAddresses == null) ? + Collections.emptySet() + : new HashSet<>(ipAddresses); + this.macAddress = mac; + this.vlan = vlan; + } + + /** + * Returns the connection point this address information is bound to. + * + * @return the connection point + */ + public ConnectPoint connectPoint() { + return connectPoint; + } + + /** + * Returns the set of interface IP addresses. + * + * @return the interface IP addresses + */ + public Set ipAddresses() { + return ipAddresses; + } + + /** + * Returns the MAC address. + * + * @return the MAC address + */ + public MacAddress mac() { + return macAddress; + } + + /** + * Returns the VLAN ID. + * + * @return the VLAN ID + */ + public VlanId vlan() { + return vlan; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (!(other instanceof PortAddresses)) { + return false; + } + + PortAddresses otherPa = (PortAddresses) other; + + return Objects.equals(this.connectPoint, otherPa.connectPoint) + && Objects.equals(this.ipAddresses, otherPa.ipAddresses) + && Objects.equals(this.macAddress, otherPa.macAddress) + && Objects.equals(this.vlan, otherPa.vlan); + } + + @Override + public int hashCode() { + return Objects.hash(connectPoint, ipAddresses, macAddress, vlan); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("connect-point", connectPoint) + .add("ip-addresses", ipAddresses) + .add("mac-address", macAddress) + .add("vlan", vlan) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/package-info.java new file mode 100644 index 00000000..4f2bc7c4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/host/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * End-station host model & related services API definitions. + */ +package org.onosproject.net.host; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/ConnectivityIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/ConnectivityIntent.java new file mode 100644 index 00000000..7caee3e8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/ConnectivityIntent.java @@ -0,0 +1,187 @@ +/* + * Copyright 2014-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.intent; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.Link; +import org.onosproject.net.NetworkResource; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Abstraction of connectivity intent for traffic matching some criteria. + */ +@Beta +public abstract class ConnectivityIntent extends Intent { + + // TODO: other forms of intents should be considered for this family: + // point-to-point with constraints (waypoints/obstacles) + // multi-to-single point with constraints (waypoints/obstacles) + // single-to-multi point with constraints (waypoints/obstacles) + // concrete path (with alternate) + // ... + + private final TrafficSelector selector; + private final TrafficTreatment treatment; + private final List constraints; + + /** + * Creates a connectivity intent that matches on the specified selector + * and applies the specified treatment. + *

+ * Path will be optimized based on the first constraint if one is given. + *

+ * + * @param appId application identifier + * @param key explicit key to use for intent + * @param resources required network resources (optional) + * @param selector traffic selector + * @param treatment treatment + * @param constraints optional prioritized list of constraints + * @param priority priority to use for flows generated by this intent + * @throws NullPointerException if the selector or treatment is null + */ + protected ConnectivityIntent(ApplicationId appId, + Key key, + Collection resources, + TrafficSelector selector, + TrafficTreatment treatment, + List constraints, + int priority) { + super(appId, key, resources, priority); + this.selector = checkNotNull(selector); + this.treatment = checkNotNull(treatment); + this.constraints = checkNotNull(constraints); + } + + /** + * Constructor for serializer. + */ + protected ConnectivityIntent() { + super(); + this.selector = null; + this.treatment = null; + this.constraints = Collections.emptyList(); + } + + /** + * Abstract builder for connectivity intents. + */ + public abstract static class Builder extends Intent.Builder { + protected TrafficSelector selector = DefaultTrafficSelector.emptySelector(); + protected TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); + protected List constraints = ImmutableList.of(); + + @Override + public Builder appId(ApplicationId appId) { + return (Builder) super.appId(appId); + } + + @Override + public Builder key(Key key) { + return (Builder) super.key(key); + } + + @Override + public Builder priority(int priority) { + return (Builder) super.priority(priority); + } + + + /** + * Sets the traffic selector for the intent that will be built. + * + * @param selector selector to use for built intent + * @return this builder + */ + public Builder selector(TrafficSelector selector) { + this.selector = selector; + return this; + } + + /** + * Sets the traffic treatment for the intent that will be built. + * + * @param treatment treatment to use for built intent + * @return this builder + */ + public Builder treatment(TrafficTreatment treatment) { + this.treatment = treatment; + return this; + } + + /** + * Sets the constraints for the intent that will be built. + * + * @param constraints constraints to use for built intent + * @return this builder + */ + public Builder constraints(List constraints) { + this.constraints = ImmutableList.copyOf(constraints); + return this; + } + } + + + /** + * Returns the match specifying the type of traffic. + * + * @return traffic match + */ + public TrafficSelector selector() { + return selector; + } + + /** + * Returns the action applied to the traffic. + * + * @return applied action + */ + public TrafficTreatment treatment() { + return treatment; + } + + /** + * Returns the set of connectivity constraints. + * + * @return list of intent constraints + */ + public List constraints() { + return constraints; + } + + /** + * Produces a collection of network resources from the given links. + * + * @param links collection of links + * @return collection of link resources + */ + protected static Collection resources(Collection links) { + return ImmutableSet.copyOf(links); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Constraint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Constraint.java new file mode 100644 index 00000000..03acf17c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Constraint.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 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.intent; + +import com.google.common.annotations.Beta; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.resource.link.LinkResourceService; + +/** + * Representation of a connectivity constraint capable of evaluating a link + * and determining the cost of traversing that link in the context of this + * constraint. + */ +@Beta +public interface Constraint { + + // TODO: Consider separating cost vs viability. + + /** + * Evaluates the specified link and provides the cost for its traversal. + * + * @param link link to be evaluated + * @param resourceService resource service for validating availability of + * link resources + * @return cost of link traversal + */ + double cost(Link link, LinkResourceService resourceService); + + /** + * Validates that the specified path satisfies the constraint. + * + * @param path path to be validated + * @param resourceService resource service for validating availability of + * link resources + * @return cost of link traversal + */ + boolean validate(Path path, LinkResourceService resourceService); + +} 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 new file mode 100644 index 00000000..0646a003 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java @@ -0,0 +1,110 @@ +/* + * 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.intent; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; +import org.onosproject.core.ApplicationId; +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; + +/** + * An intent that enables to tell flow level operation. + * This instance holds a collection of flow rules that may be executed in parallel. + */ +@Beta +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. + * + * @param appId application id + * @param flowRules flow rules to be set + * @param resources network resource to be set + */ + public FlowRuleIntent(ApplicationId appId, List flowRules, Collection resources) { + this(appId, null, flowRules, resources); + } + + /** + * Creates an flow rule intent with the specified key, flow rules to be set, and + * required network resources. + * + * @param appId application id + * @param key key + * @param flowRules flow rules + * @param resources network resources + */ + public FlowRuleIntent(ApplicationId appId, Key key, Collection flowRules, + Collection resources) { + super(appId, key, resources, DEFAULT_INTENT_PRIORITY); + this.flowRules = ImmutableList.copyOf(checkNotNull(flowRules)); + } + + /** + * Constructor for serializer. + */ + protected FlowRuleIntent() { + super(); + this.flowRules = null; + } + + /** + * Returns a collection of flow rules to be set. + * + * @return a collection of flow rules + */ + public Collection flowRules() { + return flowRules; + } + + @Override + public boolean isInstallable() { + return true; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("id", id()) + .add("key", key()) + .add("appId", appId()) + .add("resources", resources()) + .add("flowRule", flowRules) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/HostToHostIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/HostToHostIntent.java new file mode 100644 index 00000000..bd4219ad --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/HostToHostIntent.java @@ -0,0 +1,194 @@ +/* + * Copyright 2014-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.intent; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableSet; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.HostId; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Abstraction of end-station to end-station bidirectional connectivity. + */ +@Beta +public final class HostToHostIntent extends ConnectivityIntent { + + private final HostId one; + private final HostId two; + + /** + * Returns a new host to host intent builder. + * + * @return host to host intent builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder of a host to host intent. + */ + public static final class Builder extends ConnectivityIntent.Builder { + HostId one; + HostId two; + + private Builder() { + // Hide constructor + } + + @Override + public Builder appId(ApplicationId appId) { + return (Builder) super.appId(appId); + } + + @Override + public Builder key(Key key) { + return (Builder) super.key(key); + } + + @Override + public Builder selector(TrafficSelector selector) { + return (Builder) super.selector(selector); + } + + @Override + public Builder treatment(TrafficTreatment treatment) { + return (Builder) super.treatment(treatment); + } + + @Override + public Builder constraints(List constraints) { + return (Builder) super.constraints(constraints); + } + + @Override + public Builder priority(int priority) { + return (Builder) super.priority(priority); + } + + /** + * Sets the first host of the intent that will be built. + * + * @param one first host + * @return this builder + */ + public Builder one(HostId one) { + this.one = one; + return this; + } + + /** + * Sets the second host of the intent that will be built. + * + * @param two second host + * @return this builder + */ + public Builder two(HostId two) { + this.two = two; + return this; + } + + /** + * Builds a host to host intent from the accumulated parameters. + * + * @return point to point intent + */ + public HostToHostIntent build() { + + return new HostToHostIntent( + appId, + key, + one, + two, + selector, + treatment, + constraints, + priority + ); + } + } + + + /** + * Creates a new host-to-host intent with the supplied host pair. + * + * @param appId application identifier + * @param key intent key + * @param one first host + * @param two second host + * @param selector action + * @param treatment ingress port + * @param constraints optional prioritized list of path selection constraints + * @param priority priority to use for flows generated by this intent + * @throws NullPointerException if {@code one} or {@code two} is null. + */ + private HostToHostIntent(ApplicationId appId, Key key, + HostId one, HostId two, + TrafficSelector selector, + TrafficTreatment treatment, + List constraints, + int priority) { + super(appId, key, ImmutableSet.of(one, two), selector, treatment, + constraints, priority); + + // TODO: consider whether the case one and two are same is allowed + this.one = checkNotNull(one); + this.two = checkNotNull(two); + + } + + /** + * Returns identifier of the first host. + * + * @return first host identifier + */ + public HostId one() { + return one; + } + + /** + * Returns identifier of the second host. + * + * @return second host identifier + */ + public HostId two() { + return two; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("id", id()) + .add("key", key()) + .add("appId", appId()) + .add("priority", priority()) + .add("resources", resources()) + .add("selector", selector()) + .add("treatment", treatment()) + .add("constraints", constraints()) + .add("one", one) + .add("two", two) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Intent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Intent.java new file mode 100644 index 00000000..077fd895 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Intent.java @@ -0,0 +1,218 @@ +/* + * Copyright 2014-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.intent; + +import java.util.Collection; +import java.util.Objects; + +import com.google.common.annotations.Beta; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.IdGenerator; +import org.onosproject.net.NetworkResource; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +/** + * Abstraction of an application level intent. + *

+ * Make sure that an Intent should be immutable when a new type is defined. + *

+ */ +@Beta +public abstract class Intent { + + private final IntentId id; + + private final ApplicationId appId; + private final Key key; + + private final int priority; + public static final int DEFAULT_INTENT_PRIORITY = 100; + public static final int MAX_PRIORITY = (1 << 16) - 1; + public static final int MIN_PRIORITY = 1; + + private final Collection resources; + + private static IdGenerator idGenerator; + + /** + * Constructor for serializer. + */ + protected Intent() { + this.id = null; + this.appId = null; + this.key = null; + this.resources = null; + this.priority = DEFAULT_INTENT_PRIORITY; + } + + /** + * Creates a new intent. + * + * @param appId application identifier + * @param key optional key + * @param resources required network resources (optional) + * @param priority flow rule priority + */ + protected Intent(ApplicationId appId, + Key key, + Collection resources, + int priority) { + checkState(idGenerator != null, "Id generator is not bound."); + checkArgument(priority <= MAX_PRIORITY && priority >= MIN_PRIORITY); + this.id = IntentId.valueOf(idGenerator.getNewId()); + this.appId = checkNotNull(appId, "Application ID cannot be null"); + this.key = (key != null) ? key : Key.of(id.fingerprint(), appId); + this.priority = priority; + this.resources = checkNotNull(resources); + } + + /** + * Abstract builder for intents. + */ + public abstract static class Builder { + protected ApplicationId appId; + protected Key key; + protected int priority = Intent.DEFAULT_INTENT_PRIORITY; + + /** + * Sets the application id for the intent that will be built. + * + * @param appId application id to use for built intent + * @return this builder + */ + public Builder appId(ApplicationId appId) { + this.appId = appId; + return this; + } + + /** + * Sets the key for the intent that will be built. + * + * @param key key to use for built intent + * @return this builder + */ + public Builder key(Key key) { + this.key = key; + return this; + } + + /** + * Sets the priority for the intent that will be built. + * + * @param priority priority to use for built intent + * @return this builder + */ + public Builder priority(int priority) { + this.priority = priority; + return this; + } + + } + + /** + * Returns the intent identifier. + * + * @return intent fingerprint + */ + public IntentId id() { + return id; + } + + /** + * Returns the identifier of the application that requested the intent. + * + * @return application identifier + */ + public ApplicationId appId() { + return appId; + } + + /** + * Returns the priority of the intent. + * + * @return intent priority + */ + public int priority() { + return priority; + } + + /** + * Returns the collection of resources required for this intent. + * + * @return collection of resources; may be null + */ + public Collection resources() { + return resources; + } + + /** + * Indicates whether or not the intent is installable. + * + * @return true if installable + */ + public boolean isInstallable() { + return false; + } + + @Override + public final int hashCode() { + return id.hashCode(); + } + + @Override + public final boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final Intent other = (Intent) obj; + return this.id().equals(other.id()); + } + + /** + * Binds an id generator for unique intent id generation. + * + * Note: A generator cannot be bound if there is already a generator bound. + * + * @param newIdGenerator id generator + */ + public static void bindIdGenerator(IdGenerator newIdGenerator) { + checkState(idGenerator == null, "Id generator is already bound."); + idGenerator = checkNotNull(newIdGenerator); + } + + /** + * Unbinds an id generator. + * + * Note: The caller must provide the old id generator to succeed. + * + * @param oldIdGenerator the current id generator + */ + public static void unbindIdGenerator(IdGenerator oldIdGenerator) { + if (Objects.equals(idGenerator, oldIdGenerator)) { + idGenerator = null; + } + } + + public Key key() { + return key; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentBatchDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentBatchDelegate.java new file mode 100644 index 00000000..e4babfb1 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentBatchDelegate.java @@ -0,0 +1,35 @@ +/* + * Copyright 2014-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.intent; + +import com.google.common.annotations.Beta; + +import java.util.Collection; + +/** + * Facade for receiving notifications from the intent batch service. + */ +@Beta +public interface IntentBatchDelegate { + + /** + * Submits the specified batch of intent operations for processing. + * + * @param operations batch of operations + */ + void execute(Collection operations); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentClockService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentClockService.java new file mode 100644 index 00000000..d0dbacf8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentClockService.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.net.intent; + +import com.google.common.annotations.Beta; +import org.onosproject.store.Timestamp; + +/** + * Logical clock service that issues per-intent timestamps. + */ +@Beta +public interface IntentClockService { + + /** + * Returns a new timestamp for the specified intent. + * + * @param intentId identifier for the intent. + * @return timestamp + */ + Timestamp getTimestamp(IntentId intentId); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentCompiler.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentCompiler.java new file mode 100644 index 00000000..9a059be8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentCompiler.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014 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.intent; + +import com.google.common.annotations.Beta; +import org.onosproject.net.resource.link.LinkResourceAllocations; + +import java.util.List; +import java.util.Set; + +/** + * Abstraction of a compiler which is capable of taking an intent + * and translating it to other, potentially installable, intents. + * + * @param the type of intent + */ +@Beta +public interface IntentCompiler { + /** + * Compiles the specified intent into other intents. + * + * @param intent intent to be compiled + * @param installable previously compilation result; optional + * @param resources previously allocated resources; optional + * @return list of resulting intents + * @throws IntentException if issues are encountered while compiling the intent + */ + List compile(T intent, List installable, + Set resources); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentData.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentData.java new file mode 100644 index 00000000..e24e14e0 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentData.java @@ -0,0 +1,327 @@ +/* + * 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.intent; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; +import org.onosproject.cluster.NodeId; +import org.onosproject.store.Timestamp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.intent.IntentState.*; + +/** + * A wrapper class that contains an intents, its state, and other metadata for + * internal use. + */ +@Beta +public class IntentData { //FIXME need to make this "immutable" + // manager should be able to mutate a local copy while processing + + private static final Logger log = LoggerFactory.getLogger(IntentData.class); + + private final Intent intent; + + private final IntentState request; //TODO perhaps we want a full fledged object for requests + private IntentState state; + private Timestamp version; + private NodeId origin; + private int errorCount; + + private List installables; + + /** + * Creates a new intent data object. + * + * @param intent intent this metadata references + * @param state intent state + * @param version version of the intent for this key + */ + public IntentData(Intent intent, IntentState state, Timestamp version) { + this.intent = intent; + this.state = state; + this.request = state; + this.version = version; + } + + /** + * Copy constructor. + * + * @param intentData intent data to copy + */ + public IntentData(IntentData intentData) { + checkNotNull(intentData); + + intent = intentData.intent; + state = intentData.state; + request = intentData.request; + version = intentData.version; + origin = intentData.origin; + installables = intentData.installables; + errorCount = intentData.errorCount; + } + + // kryo constructor + protected IntentData() { + intent = null; + request = null; + } + + /** + * Returns the intent this metadata references. + * + * @return intent + */ + public Intent intent() { + return intent; + } + + /** + * Returns the state of the intent. + * + * @return intent state + */ + public IntentState state() { + return state; + } + + public IntentState request() { + return request; + } + + /** + * Returns the intent key. + * + * @return intent key + */ + public Key key() { + return intent.key(); + } + + /** + * Returns the version of the intent for this key. + * + * @return intent version + */ + public Timestamp version() { + return version; + } + + /** + * Sets the origin, which is the node that created the intent. + * + * @param origin origin instance + */ + public void setOrigin(NodeId origin) { + this.origin = origin; + } + + /** + * Returns the origin node that created this intent. + * + * @return origin node ID + */ + public NodeId origin() { + return origin; + } + + /** + * Updates the state of the intent to the given new state. + * + * @param newState new state of the intent + */ + public void setState(IntentState newState) { + this.state = newState; + } + + /** + * Sets the version for this intent data. + *

+ * The store should call this method only once when the IntentData is + * first passed into the pending map. Ideally, an IntentData is timestamped + * on the same thread that the called used to submit the intents. + *

+ * + * @param version the version/timestamp for this intent data + */ + public void setVersion(Timestamp version) { + this.version = version; + } + + /** + * Increments the error count for this intent. + */ + public void incrementErrorCount() { + errorCount++; + } + + /** + * Sets the error count for this intent. + * + * @param newCount new count + */ + public void setErrorCount(int newCount) { + errorCount = newCount; + } + + /** + * Returns the number of times that this intent has encountered an error + * during installation or withdrawal. + * + * @return error count + */ + public int errorCount() { + return errorCount; + } + + /** + * Sets the intent installables to the given list of intents. + * + * @param installables list of installables for this intent + */ + public void setInstallables(List installables) { + this.installables = ImmutableList.copyOf(installables); + } + + /** + * Returns the installables associated with this intent. + * + * @return list of installable intents + */ + public List installables() { + return installables != null ? installables : Collections.emptyList(); + } + + /** + * Determines whether an intent data update is allowed. The update must + * either have a higher version than the current data, or the state + * transition between two updates of the same version must be sane. + * + * @param currentData existing intent data in the store + * @param newData new intent data update proposal + * @return true if we can apply the update, otherwise false + */ + public static boolean isUpdateAcceptable(IntentData currentData, IntentData newData) { + + if (currentData == null) { + return true; + } else if (currentData.version().isOlderThan(newData.version())) { + return true; + } else if (currentData.version().isNewerThan(newData.version())) { + return false; + } + + // current and new data versions are the same + IntentState currentState = currentData.state(); + IntentState newState = newData.state(); + + switch (newState) { + case INSTALLING: + if (currentState == INSTALLING) { + return false; + } + // FALLTHROUGH + case INSTALLED: + if (currentState == INSTALLED) { + return false; + } else if (currentState == WITHDRAWING || currentState == WITHDRAWN + || currentState == PURGE_REQ) { + log.warn("Invalid state transition from {} to {} for intent {}", + currentState, newState, newData.key()); + return false; + } + return true; + + case WITHDRAWING: + if (currentState == WITHDRAWING) { + return false; + } + // FALLTHROUGH + case WITHDRAWN: + if (currentState == WITHDRAWN) { + return false; + } else if (currentState == INSTALLING || currentState == INSTALLED + || currentState == PURGE_REQ) { + log.warn("Invalid state transition from {} to {} for intent {}", + currentState, newState, newData.key()); + return false; + } + return true; + + case FAILED: + if (currentState == FAILED) { + return false; + } + return true; + + case CORRUPT: + if (currentState == CORRUPT) { + return false; + } + return true; + + case PURGE_REQ: + // TODO we should enforce that only WITHDRAWN intents can be purged + return true; + + case COMPILING: + case RECOMPILING: + case INSTALL_REQ: + case WITHDRAW_REQ: + default: + log.warn("Invalid state {} for intent {}", newState, newData.key()); + return false; + } + } + + @Override + public int hashCode() { + return Objects.hash(intent, version); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final IntentData other = (IntentData) obj; + return Objects.equals(this.intent, other.intent) + && Objects.equals(this.version, other.version); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("key", key()) + .add("state", state()) + .add("version", version()) + .add("intent", intent()) + .add("origin", origin()) + .add("installables", installables()) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentEvent.java new file mode 100644 index 00000000..b27a5074 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentEvent.java @@ -0,0 +1,146 @@ +/* + * Copyright 2014-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.intent; + +import com.google.common.annotations.Beta; +import org.onosproject.event.AbstractEvent; + +/** + * A class to represent an intent related event. + */ +@Beta +public class IntentEvent extends AbstractEvent { + + public enum Type { + /** + * Signifies that an intent is to be installed or reinstalled. + */ + INSTALL_REQ, + + /** + * Signifies that an intent has been successfully installed. + */ + INSTALLED, + + /** + * Signifies that an intent has failed compilation and that it cannot + * be satisfied by the network at this time. + */ + FAILED, + + /** + * Signifies that an intent will be withdrawn. + */ + WITHDRAW_REQ, + + /** + * Signifies that an intent has been withdrawn from the system. + */ + WITHDRAWN, + + /** + * Signifies that an intent has failed installation or withdrawal, but + * still hold some or all of its resources. + * (e.g. link reservations, flow rules on the data plane, etc.) + */ + CORRUPT, + + /** + * Signifies that an intent has been purged from the system. + */ + PURGED + } + + /** + * Creates an event of a given type and for the specified intent and the + * current time. + * + * @param type event type + * @param intent subject intent + * @param time time the event created in milliseconds since start of epoch + */ + public IntentEvent(Type type, Intent intent, long time) { + super(type, intent, time); + } + + /** + * Creates an event of a given type and for the specified intent and the + * current time. + * + * @param type event type + * @param intent subject intent + */ + public IntentEvent(Type type, Intent intent) { + super(type, intent); + } + + /** + * Creates an IntentEvent based on the state contained in the given intent + * data. Some states are not sent as external events, and these states will + * return null events. + * + * @param data the intent data to create an event for + * @return new intent event if the state is valid, otherwise null. + */ + public static IntentEvent getEvent(IntentData data) { + return getEvent(data.state(), data.intent()); + } + + /** + * Creates an IntentEvent based on the given state and intent. Some states + * are not sent as external events, and these states will return null events. + * + * @param state new state of the intent + * @param intent intent to put in event + * @return new intent event if the state is valid, otherwise null. + */ + public static IntentEvent getEvent(IntentState state, Intent intent) { + Type type; + switch (state) { + case INSTALL_REQ: + type = Type.INSTALL_REQ; + break; + case INSTALLED: + type = Type.INSTALLED; + break; + case WITHDRAW_REQ: + type = Type.WITHDRAW_REQ; + break; + case WITHDRAWN: + type = Type.WITHDRAWN; + break; + case FAILED: + type = Type.FAILED; + break; + case CORRUPT: + type = Type.CORRUPT; + break; + case PURGE_REQ: + type = Type.PURGED; + break; + + // fallthrough to default from here + case COMPILING: + case INSTALLING: + case RECOMPILING: + case WITHDRAWING: + default: + return null; + } + return new IntentEvent(type, intent); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentException.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentException.java new file mode 100644 index 00000000..3ac1df50 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentException.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 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.intent; + +import com.google.common.annotations.Beta; + +/** + * Represents an intent related error. + */ +@Beta +public class IntentException extends RuntimeException { + + private static final long serialVersionUID = 1907263634145241319L; + + /** + * Constructs an exception with no message and no underlying cause. + */ + public IntentException() { + } + + /** + * Constructs an exception with the specified message. + * + * @param message the message describing the specific nature of the error + */ + public IntentException(String message) { + super(message); + } + + /** + * Constructs an exception with the specified message and the underlying cause. + * + * @param message the message describing the specific nature of the error + * @param cause the underlying cause of this error + */ + public IntentException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentExtensionService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentExtensionService.java new file mode 100644 index 00000000..d7c7c641 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentExtensionService.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014-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.intent; + +import com.google.common.annotations.Beta; + +import java.util.Map; + +/** + * Service for extending the capability of intent framework by + * adding additional compilers or/and installers. + */ +@Beta +public interface IntentExtensionService { + /** + * Registers the specified compiler for the given intent class. + * + * @param cls intent class + * @param compiler intent compiler + * @param the type of intent + */ + void registerCompiler(Class cls, IntentCompiler compiler); + + /** + * Unregisters the compiler for the specified intent class. + * + * @param cls intent class + * @param the type of intent + */ + void unregisterCompiler(Class cls); + + /** + * Returns immutable set of bindings of currently registered intent compilers. + * + * @return the set of compiler bindings + */ + Map, IntentCompiler> getCompilers(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentId.java new file mode 100644 index 00000000..b9a30d2d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentId.java @@ -0,0 +1,87 @@ +/* + * Copyright 2014-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.intent; + +import com.google.common.annotations.Beta; +import org.onosproject.net.newresource.ResourceConsumer; + +/** + * Intent identifier suitable as an external key. + *

This class is immutable.

+ */ +@Beta +public final class IntentId implements ResourceConsumer { + + private final long value; + + /** + * Creates an intent identifier from the specified long representation. + * + * @param value long value + * @return intent identifier + */ + public static IntentId valueOf(long value) { + return new IntentId(value); + } + + /** + * Constructor for serializer. + */ + IntentId() { + this.value = 0; + } + + /** + * Constructs the ID corresponding to a given long value. + * + * @param value the underlying value of this ID + */ + IntentId(long value) { + this.value = value; + } + + /** + * Returns the backing value. + * + * @return the value + */ + public long fingerprint() { + return value; + } + + @Override + public int hashCode() { + return Long.hashCode(value); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof IntentId)) { + return false; + } + IntentId that = (IntentId) obj; + return this.value == that.value; + } + + @Override + public String toString() { + return "0x" + Long.toHexString(value); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentListener.java new file mode 100644 index 00000000..4858c7ed --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentListener.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 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.intent; + +import com.google.common.annotations.Beta; +import org.onosproject.event.EventListener; + +/** + * Listener for {@link IntentEvent intent events}. + */ +@Beta +public interface IntentListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentOperation.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentOperation.java new file mode 100644 index 00000000..1b51b4f3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentOperation.java @@ -0,0 +1,124 @@ +/* + * Copyright 2014-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.intent; + + +import com.google.common.annotations.Beta; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Abstraction of an intent-related operation, e.g. add, remove, replace. + */ +@Beta +public final class IntentOperation { + + private final Type type; + private final Intent intent; + + /** + * Operation type. + */ + public enum Type { + /** + * Indicates that an intent should be added. + */ + SUBMIT, + + /** + * Indicates that an intent should be removed. + */ + WITHDRAW, + } + + /** + * Creates an intent operation. + * + * @param type operation type + * @param intent intent subject + */ + public IntentOperation(Type type, Intent intent) { + this.type = checkNotNull(type); + this.intent = intent; + } + + /** + * Returns the type of the operation. + * + * @return operation type + */ + public Type type() { + return type; + } + + /** + * Returns the identifier of the intent to which this operation applies. + * + * @return intent identifier + */ + public IntentId intentId() { + return intent.id(); + } + + /** + * Returns the key for this intent. + * + * @return key value + */ + public Key key() { + return intent.key(); + } + + /** + * Returns the intent to which this operation applied. For remove, + * this can be null. + * + * @return intent that is the subject of the operation; null for remove + */ + public Intent intent() { + return intent; + } + + @Override + public int hashCode() { + return Objects.hash(type, intent); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final IntentOperation other = (IntentOperation) obj; + return Objects.equals(this.type, other.type) && + Objects.equals(this.intent, other.intent); + } + + + @Override + public String toString() { + return toStringHelper(this) + .add("type", type) + .add("intent", intent) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentService.java new file mode 100644 index 00000000..8533cebc --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentService.java @@ -0,0 +1,123 @@ +/* + * Copyright 2014-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.intent; + + +import com.google.common.annotations.Beta; +import org.onosproject.event.ListenerService; + +import java.util.List; + +/** + * Service for application submitting or withdrawing their intents. + */ +@Beta +public interface IntentService + extends ListenerService { + + /** + * Submits an intent into the system. + *

+ * This is an asynchronous request meaning that any compiling or + * installation activities may be done at later time. + *

+ * @param intent intent to be submitted + */ + void submit(Intent intent); + + /** + * Withdraws an intent from the system. + *

+ * This is an asynchronous request meaning that the environment may be + * affected at later time. + *

+ * @param intent intent to be withdrawn + */ + void withdraw(Intent intent); + + /** + * Purges a specific intent from the system if it is FAILED or + * WITHDRAWN. Otherwise, the intent remains in its current state. + * + * @param intent intent to purge + */ + void purge(Intent intent); + + /** + * Fetches an intent based on its key. + * + * @param key key of the intent + * @return intent object if the key is found, null otherwise + */ + Intent getIntent(Key key); + + /** + * Returns an iterable of intents currently in the system. + * + * @return set of intents + */ + Iterable getIntents(); + + /** + * Returns an iterable of intent data objects currently in the system. + * + * @return set of intent data objects + */ + Iterable getIntentData(); + + /** + * Returns the number of intents currently in the system. + * + * @return number of intents + */ + long getIntentCount(); + + /** + * Retrieves the state of an intent by its identifier. + * + * @param intentKey intent identifier + * @return the intent state or null if one with the given identifier is not + * found + */ + IntentState getIntentState(Key intentKey); + + /** + * Returns the list of the installable events associated with the specified + * top-level intent. + * + * @param intentKey top-level intent identifier + * @return compiled installable intents + */ + List getInstallableIntents(Key intentKey); + + /** + * Signifies whether the local node is responsible for processing the given + * intent key. + * + * @param intentKey intent key to check + * @return true if the local node is responsible for the intent key, + * otherwise false + */ + boolean isLocal(Key intentKey); + + /** + * Returns the list of intent requests pending processing. + * + * @return intents pending processing + */ + Iterable getPending(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentState.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentState.java new file mode 100644 index 00000000..1e5fd054 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentState.java @@ -0,0 +1,117 @@ +/* + * Copyright 2014-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.intent; + +import com.google.common.annotations.Beta; + +/** + * Representation of the phases an intent may attain during its lifecycle. + */ +@Beta +public enum IntentState { + + /** + * Signifies that the intent has been submitted and will start compiling + * shortly. However, this compilation may not necessarily occur on the + * local controller instance. + *

+ * All intent in the runtime take this state first. + *

+ * Intents will also pass through this state when they are updated. + *

+ */ + INSTALL_REQ, // TODO submit_REQ? + + /** + * Signifies that the intent is being compiled into installable intents. + * This is a transitional state after which the intent will enter either + * {@link #FAILED} state or {@link #INSTALLING} state. + */ + COMPILING, //TODO do we really need this? + + /** + * Signifies that the resulting installable intents are being installed + * into the network environment. This is a transitional state after which + * the intent will enter either {@link #INSTALLED} state or + * {@link #RECOMPILING} state. + */ + INSTALLING, + + /** + * The intent has been successfully installed. This is a state where the + * intent may remain parked until it is withdrawn by the application or + * until the network environment changes in some way to make the original + * set of installable intents untenable. + */ + INSTALLED, + + /** + * Signifies that the intent is being recompiled into installable intents + * as an attempt to adapt to an anomaly in the network environment. + * This is a transitional state after which the intent will enter either + * {@link #FAILED} state or {@link #INSTALLING} state. + *

+ * Exit to the {@link #FAILED} state may be caused by failure to compile + * or by compiling into the same set of installable intents which have + * previously failed to be installed. + *

+ */ + RECOMPILING, // TODO perhaps repurpose as BROKEN. + + /** + * Indicates that an application has requested that an intent be withdrawn. + * It will start withdrawing shortly, but not necessarily on this instance. + * Intents can also be parked here if it is impossible to withdraw them. + */ + WITHDRAW_REQ, + + /** + * Indicates that the intent is being withdrawn. This is a transitional + * state, triggered by invocation of the + * {@link IntentService#withdraw(Intent)} but one with only one outcome, + * which is the the intent being placed in the {@link #WITHDRAWN} state. + */ + WITHDRAWING, + + /** + * Indicates that the intent has been successfully withdrawn. + */ + WITHDRAWN, + + /** + * Signifies that the intent has failed to be installed and cannot be + * satisfied given current network conditions. But, the framework will + * reattempt to install it when network conditions change until it is + * withdrawn by an application. + */ + FAILED, //TODO consider renaming to UNSATISFIABLE + + /** + * Signifies that an intent has failed either installation or withdrawal, + * and still hold some or all of its resources. + * (e.g. link reservations, flow rules on the data plane, etc.) + */ + CORRUPT, //TODO consider renaming to ERROR + + /** + * Indicates that the intent should be purged from the database. + *

+ * Note: This operation will only be performed if the intent is already + * in WITHDRAWN or FAILED. + *

+ */ + PURGE_REQ +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentStore.java new file mode 100644 index 00000000..167ba152 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentStore.java @@ -0,0 +1,143 @@ +/* + * Copyright 2014-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.intent; + +import com.google.common.annotations.Beta; +import org.onosproject.store.Store; + +import java.util.List; + +/** + * Manages inventory of end-station intents; not intended for direct use. + */ +@Beta +public interface IntentStore extends Store { + + /** + * Returns the number of intents in the store. + * + * @return the number of intents in the store + */ + long getIntentCount(); + + /** + * Returns an iterable of all intents in the store. + * + * @return iterable of all intents + */ + Iterable getIntents(); + + + /** + * Returns an iterable of all intent data objects in the store. + * + * @param localOnly should only intents for which this instance is master + * be returned + * @param olderThan specified duration in milliseconds (0 for "now") + * @return iterable of all intent data objects + */ + Iterable getIntentData(boolean localOnly, long olderThan); + + /** + * Returns the state of the specified intent. + * + * @param intentKey intent identification + * @return current intent state + */ + IntentState getIntentState(Key intentKey); + + /** + * Returns the list of the installable events associated with the specified + * original intent. + * + * @param intentKey original intent identifier + * @return compiled installable intents, or null if no installables exist + */ + List getInstallableIntents(Key intentKey); + + /** + * Writes an IntentData object to the store. + * + * @param newData new intent data to write + */ + void write(IntentData newData); + + /** + * Writes a batch of IntentData objects to the store. A batch has no + * semantics, this is simply a convenience API. + * + * @param updates collection of intent data objects to write + */ + void batchWrite(Iterable updates); + + /** + * Returns the intent with the specified identifier. + * + * @param key key + * @return intent or null if not found + */ + Intent getIntent(Key key); + + /** + * Returns the intent data object associated with the specified key. + * + * @param key key to look up + * @return intent data object + */ + IntentData getIntentData(Key key); + + /** + * Adds a new operation, which should be persisted and delegated. + * + * @param intent operation + */ + void addPending(IntentData intent); + + /** + * Checks to see whether the calling instance is the master for processing + * this intent, or more specifically, the key contained in this intent. + * + * @param intentKey intentKey to check + * @return true if master; false, otherwise + */ + //TODO better name + boolean isMaster(Key intentKey); + + /** + * Returns the intent requests pending processing. + * + * @return pending intents + */ + Iterable getPending(); + + /** + * Returns the intent data objects that are pending processing. + * + * @return pending intent data objects + */ + Iterable getPendingData(); + + /** + * Returns the intent data objects that are pending processing for longer + * than the specified duration. + * + * @param localOnly should only intents for which this instance is master + * be returned + * @param olderThan specified duration in milliseconds (0 for "now") + * @return pending intent data objects + */ + Iterable getPendingData(boolean localOnly, long olderThan); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentStoreDelegate.java new file mode 100644 index 00000000..fd99881c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/IntentStoreDelegate.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014-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.intent; + +import com.google.common.annotations.Beta; +import org.onosproject.store.StoreDelegate; + +/** + * Intent store delegate abstraction. + */ +@Beta +public interface IntentStoreDelegate extends StoreDelegate { + + /** + * Provides an intent data object that should be processed (compiled and + * installed) by this manager. + * + * @param intentData intent data object + */ + void process(IntentData intentData); + + /** + * Called when a new intent has been updated for which this node is the master. + * + * @param intentData intent data object + */ + default void onUpdate(IntentData intentData) { + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Key.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Key.java new file mode 100644 index 00000000..18baafc8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/Key.java @@ -0,0 +1,163 @@ +/* + * 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.intent; + +import com.google.common.annotations.Beta; +import com.google.common.hash.HashFunction; +import com.google.common.hash.Hashing; +import org.onosproject.core.ApplicationId; + +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +/** + * Key class for Intents. + */ +// TODO maybe pull this up to utils +@Beta +public abstract class Key { + + //TODO consider making this a HashCode object (worry about performance) + private final long hash; + private static final HashFunction HASH_FN = Hashing.md5(); + + protected Key(long hash) { + this.hash = hash; + } + + public long hash() { + return hash; + } + + @Override + public int hashCode() { + return Long.hashCode(hash); + } + + @Override + public abstract boolean equals(Object obj); + + /** + * Creates a key based on the provided string. + *

+ * Note: Two keys with equal value, but different appId, are not equal. + *

+ * + * @param key the provided string + * @param appId application id to associate with this key + * @return the key for the string + */ + public static Key of(String key, ApplicationId appId) { + return new StringKey(key, appId); + } + + /** + * Creates a key based on the provided long. + *

+ * Note: Two keys with equal value, but different appId, are not equal. + * Also, "10" and 10L are different. + *

+ * + * @param key the provided long + * @param appId application id to associate with this key + * @return the key for the long + */ + public static Key of(long key, ApplicationId appId) { + return new LongKey(key, appId); + } + + private static final class StringKey extends Key { + + private final ApplicationId appId; + private final String key; + + private StringKey(String key, ApplicationId appId) { + super(HASH_FN.newHasher() + .putShort(appId.id()) + .putString(key, StandardCharsets.UTF_8) + .hash().asLong()); + this.key = key; + this.appId = appId; + } + + @Override + public String toString() { + return key; + } + + // checkstyle requires this + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final StringKey other = (StringKey) obj; + return this.hash() == other.hash() && + Objects.equals(this.appId, other.appId) && + Objects.equals(this.key, other.key); + } + } + + private static final class LongKey extends Key { + + private final ApplicationId appId; + private final long key; + + private LongKey(long key, ApplicationId appId) { + super(HASH_FN.newHasher() + .putShort(appId.id()) + .putLong(key) + .hash().asLong()); + this.key = key; + this.appId = appId; + } + + @Override + public String toString() { + return "0x" + Long.toHexString(key); + } + + // checkstyle requires this + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final LongKey other = (LongKey) obj; + return this.hash() == other.hash() && + this.key == other.key && + Objects.equals(this.appId, other.appId); + } + } +} + + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/LinkCollectionIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/LinkCollectionIntent.java new file mode 100644 index 00000000..d7953fd8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/LinkCollectionIntent.java @@ -0,0 +1,241 @@ +/* + * Copyright 2014-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.intent; + +import java.util.List; +import java.util.Set; + +import com.google.common.annotations.Beta; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Link; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableSet; + +/** + * Abstraction of a connectivity intent that is implemented by a set of path + * segments. + */ +@Beta +public final class LinkCollectionIntent extends ConnectivityIntent { + + private final Set links; + + private final Set ingressPoints; + private final Set egressPoints; + + /** + * Creates a new actionable intent capable of funneling the selected + * traffic along the specified convergent tree and out the given egress + * point satisfying the specified constraints. + * + * @param appId application identifier + * @param key key to use for the intent + * @param selector traffic match + * @param treatment action + * @param links traversed links + * @param ingressPoints ingress points + * @param egressPoints egress points + * @param constraints optional list of constraints + * @param priority priority to use for the flows generated by this intent + * @throws NullPointerException {@code path} is null + */ + private LinkCollectionIntent(ApplicationId appId, + Key key, + TrafficSelector selector, + TrafficTreatment treatment, + Set links, + Set ingressPoints, + Set egressPoints, + List constraints, + int priority) { + super(appId, key, resources(links), selector, treatment, constraints, priority); + this.links = links; + this.ingressPoints = ingressPoints; + this.egressPoints = egressPoints; + } + + /** + * Constructor for serializer. + */ + protected LinkCollectionIntent() { + super(); + this.links = null; + this.ingressPoints = null; + this.egressPoints = null; + } + + /** + * Returns a new link collection intent builder. The application id, + * ingress point and egress points are required fields. If they are + * not set by calls to the appropriate methods, an exception will + * be thrown. + * + * @return single point to multi point builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder of a single point to multi point intent. + */ + public static final class Builder extends ConnectivityIntent.Builder { + Set links; + Set ingressPoints; + Set egressPoints; + + private Builder() { + // Hide constructor + } + + @Override + public Builder appId(ApplicationId appId) { + return (Builder) super.appId(appId); + } + + @Override + public Builder key(Key key) { + return (Builder) super.key(key); + } + + @Override + public Builder selector(TrafficSelector selector) { + return (Builder) super.selector(selector); + } + + @Override + public Builder treatment(TrafficTreatment treatment) { + return (Builder) super.treatment(treatment); + } + + @Override + public Builder constraints(List constraints) { + return (Builder) super.constraints(constraints); + } + + @Override + public Builder priority(int priority) { + return (Builder) super.priority(priority); + } + + /** + * Sets the ingress point of the single point to multi point intent + * that will be built. + * + * @param ingressPoints ingress connect points + * @return this builder + */ + public Builder ingressPoints(Set ingressPoints) { + this.ingressPoints = ImmutableSet.copyOf(ingressPoints); + return this; + } + + /** + * Sets the egress points of the single point to multi point intent + * that will be built. + * + * @param egressPoints egress connect points + * @return this builder + */ + public Builder egressPoints(Set egressPoints) { + this.egressPoints = ImmutableSet.copyOf(egressPoints); + return this; + } + + /** + * Sets the links of the link collection intent + * that will be built. + * + * @param links links for the intent + * @return this builder + */ + public Builder links(Set links) { + this.links = ImmutableSet.copyOf(links); + return this; + } + + + /** + * Builds a single point to multi point intent from the + * accumulated parameters. + * + * @return point to point intent + */ + public LinkCollectionIntent build() { + + return new LinkCollectionIntent( + appId, + key, + selector, + treatment, + links, + ingressPoints, + egressPoints, + constraints, + priority + ); + } + } + + + /** + * Returns the set of links that represent the network connections needed + * by this intent. + * + * @return Set of links for the network hops needed by this intent + */ + public Set links() { + return links; + } + + /** + * Returns the ingress points of the intent. + * + * @return the ingress points + */ + public Set ingressPoints() { + return ingressPoints; + } + + /** + * Returns the egress points of the intent. + * + * @return the egress points + */ + public Set egressPoints() { + return egressPoints; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("id", id()) + .add("key", key()) + .add("appId", appId()) + .add("priority", priority()) + .add("resources", resources()) + .add("selector", selector()) + .add("treatment", treatment()) + .add("links", links()) + .add("ingress", ingressPoints()) + .add("egress", egressPoints()) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/MplsIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/MplsIntent.java new file mode 100644 index 00000000..bf469dbe --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/MplsIntent.java @@ -0,0 +1,261 @@ +package org.onosproject.net.intent; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import com.google.common.annotations.Beta; +import org.onlab.packet.MplsLabel; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import com.google.common.base.MoreObjects; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + + +/** + * Abstraction of MPLS label-switched connectivity. + */ +@Beta +public final class MplsIntent extends ConnectivityIntent { + + private final ConnectPoint ingressPoint; + private final Optional ingressLabel; + private final ConnectPoint egressPoint; + private final Optional egressLabel; + + /** + * Creates a new point-to-point intent with the supplied ingress/egress + * ports, labels and constraints. + * + * @param appId application identifier + * @param selector traffic selector + * @param treatment treatment + * @param ingressPoint ingress port + * @param ingressLabel ingress MPLS label + * @param egressPoint egress port + * @param egressLabel egress MPLS label + * @param constraints optional list of constraints + * @param priority priority to use for flows generated by this intent + * @throws NullPointerException if {@code ingressPoint} or {@code egressPoints} is null. + */ + private MplsIntent(ApplicationId appId, + Key key, + TrafficSelector selector, + TrafficTreatment treatment, + ConnectPoint ingressPoint, + Optional ingressLabel, + ConnectPoint egressPoint, + Optional egressLabel, + List constraints, + int priority) { + + super(appId, key, Collections.emptyList(), selector, treatment, constraints, + priority); + + this.ingressPoint = checkNotNull(ingressPoint); + this.ingressLabel = checkNotNull(ingressLabel); + this.egressPoint = checkNotNull(egressPoint); + this.egressLabel = checkNotNull(egressLabel); + + checkArgument(!ingressPoint.equals(egressPoint), + "ingress and egress should be different (ingress: %s, egress: %s)", + ingressPoint, egressPoint); + } + + /** + * Returns a new MPLS intent builder. The application id, + * ingress point, egress point, ingress label and egress label are + * required fields. If they are not set by calls to the appropriate + * methods, an exception will be thrown. + * + * @return point to point builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder of an MPLS intent. + */ + public static final class Builder extends ConnectivityIntent.Builder { + ConnectPoint ingressPoint; + ConnectPoint egressPoint; + Optional ingressLabel; + Optional egressLabel; + + private Builder() { + // Hide constructor + } + + @Override + public Builder appId(ApplicationId appId) { + return (Builder) super.appId(appId); + } + + @Override + public Builder key(Key key) { + return (Builder) super.key(key); + } + + @Override + public Builder selector(TrafficSelector selector) { + return (Builder) super.selector(selector); + } + + @Override + public Builder treatment(TrafficTreatment treatment) { + return (Builder) super.treatment(treatment); + } + + @Override + public Builder constraints(List constraints) { + return (Builder) super.constraints(constraints); + } + + @Override + public Builder priority(int priority) { + return (Builder) super.priority(priority); + } + + /** + * Sets the ingress point of the point to point intent that will be built. + * + * @param ingressPoint ingress connect point + * @return this builder + */ + public Builder ingressPoint(ConnectPoint ingressPoint) { + this.ingressPoint = ingressPoint; + return this; + } + + /** + * Sets the egress point of the point to point intent that will be built. + * + * @param egressPoint egress connect point + * @return this builder + */ + public Builder egressPoint(ConnectPoint egressPoint) { + this.egressPoint = egressPoint; + return this; + } + + /** + * Sets the ingress label of the intent that will be built. + * + * @param ingressLabel ingress label + * @return this builder + */ + public Builder ingressLabel(Optional ingressLabel) { + this.ingressLabel = ingressLabel; + return this; + } + + /** + * Sets the ingress label of the intent that will be built. + * + * @param egressLabel ingress label + * @return this builder + */ + public Builder egressLabel(Optional egressLabel) { + this.egressLabel = egressLabel; + return this; + } + + /** + * Builds a point to point intent from the accumulated parameters. + * + * @return point to point intent + */ + public MplsIntent build() { + + return new MplsIntent( + appId, + key, + selector, + treatment, + ingressPoint, + ingressLabel, + egressPoint, + egressLabel, + constraints, + priority + ); + } + } + + + + /** + * Constructor for serializer. + */ + protected MplsIntent() { + super(); + this.ingressPoint = null; + this.ingressLabel = null; + this.egressPoint = null; + this.egressLabel = null; + } + + /** + * Returns the port on which the ingress traffic should be connected to + * the egress. + * + * @return ingress switch port + */ + public ConnectPoint ingressPoint() { + return ingressPoint; + } + + /** + * Returns the port on which the traffic should egress. + * + * @return egress switch port + */ + public ConnectPoint egressPoint() { + return egressPoint; + } + + + /** + * Returns the MPLS label which the ingress traffic should tagged. + * + * @return ingress MPLS label + */ + public Optional ingressLabel() { + return ingressLabel; + } + + /** + * Returns the MPLS label which the egress traffic should tagged. + * + * @return egress MPLS label + */ + public Optional egressLabel() { + return egressLabel; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("id", id()) + .add("appId", appId()) + .add("key", key()) + .add("priority", priority()) + .add("selector", selector()) + .add("treatment", treatment()) + .add("ingressPoint", ingressPoint) + .add("ingressLabel", ingressLabel) + .add("egressPoint", egressPoint) + .add("egressLabel", egressLabel) + .add("constraints", constraints()) + .toString(); + } + + + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/MplsPathIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/MplsPathIntent.java new file mode 100644 index 00000000..3c3c45ce --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/MplsPathIntent.java @@ -0,0 +1,167 @@ +package org.onosproject.net.intent; + +import java.util.List; +import java.util.Optional; + +import com.google.common.annotations.Beta; +import org.onlab.packet.MplsLabel; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.Path; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import static com.google.common.base.Preconditions.checkNotNull; + + +/** + * Abstraction of explicit MPLS label-switched path. + */ +@Beta +public final class MplsPathIntent extends PathIntent { + + private final Optional ingressLabel; + private final Optional egressLabel; + + /** + * Creates a new point-to-point intent with the supplied ingress/egress + * ports and using the specified explicit path. + * + * @param appId application identifier + * @param selector traffic selector + * @param treatment treatment + * @param path traversed links + * @param ingressLabel MPLS egress label + * @param egressLabel MPLS ingress label + * @param constraints optional list of constraints + * @param priority priority to use for flows generated by this intent + * @throws NullPointerException {@code path} is null + */ + private MplsPathIntent(ApplicationId appId, TrafficSelector selector, + TrafficTreatment treatment, Path path, Optional ingressLabel, + Optional egressLabel, List constraints, + int priority) { + super(appId, selector, treatment, path, constraints, + priority); + + this.ingressLabel = checkNotNull(ingressLabel); + this.egressLabel = checkNotNull(egressLabel); + } + + /** + * Returns a new host to host intent builder. + * + * @return host to host intent builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder of a host to host intent. + */ + public static final class Builder extends PathIntent.Builder { + private Optional ingressLabel = Optional.empty(); + private Optional egressLabel = Optional.empty(); + + private Builder() { + // Hide constructor + } + + @Override + public Builder appId(ApplicationId appId) { + return (Builder) super.appId(appId); + } + + @Override + public Builder key(Key key) { + return (Builder) super.key(key); + } + + @Override + public Builder selector(TrafficSelector selector) { + return (Builder) super.selector(selector); + } + + @Override + public Builder treatment(TrafficTreatment treatment) { + return (Builder) super.treatment(treatment); + } + + @Override + public Builder constraints(List constraints) { + return (Builder) super.constraints(constraints); + } + + @Override + public Builder priority(int priority) { + return (Builder) super.priority(priority); + } + + @Override + public Builder path(Path path) { + return (Builder) super.path(path); + } + + /** + * Sets the ingress label of the intent that will be built. + * + * @param ingressLabel ingress label + * @return this builder + */ + public Builder ingressLabel(Optional ingressLabel) { + this.ingressLabel = ingressLabel; + return this; + } + + /** + * Sets the ingress label of the intent that will be built. + * + * @param egressLabel ingress label + * @return this builder + */ + public Builder egressLabel(Optional egressLabel) { + this.egressLabel = egressLabel; + return this; + } + + + /** + * Builds a host to host intent from the accumulated parameters. + * + * @return point to point intent + */ + public MplsPathIntent build() { + + return new MplsPathIntent( + appId, + selector, + treatment, + path, + ingressLabel, + egressLabel, + constraints, + priority + ); + } + } + + + /** + * Returns the MPLS label which the ingress traffic should tagged. + * + * @return ingress MPLS label + */ + public Optional ingressLabel() { + return ingressLabel; + } + + /** + * Returns the MPLS label which the egress traffic should tagged. + * + * @return egress MPLS label + */ + public Optional egressLabel() { + return egressLabel; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/MultiPointToSinglePointIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/MultiPointToSinglePointIntent.java new file mode 100644 index 00000000..ac6061c7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/MultiPointToSinglePointIntent.java @@ -0,0 +1,223 @@ +/* + * Copyright 2014-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.intent; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Abstraction of multiple source to single destination connectivity intent. + */ +@Beta +public final class MultiPointToSinglePointIntent extends ConnectivityIntent { + + private final Set ingressPoints; + private final ConnectPoint egressPoint; + + /** + * Creates a new multi-to-single point connectivity intent for the specified + * traffic selector and treatment. + * + * @param appId application identifier + * @param key intent key + * @param selector traffic selector + * @param treatment treatment + * @param ingressPoints set of ports from which ingress traffic originates + * @param egressPoint port to which traffic will egress + * @param constraints constraints to apply to the intent + * @param priority priority to use for flows generated by this intent + * @throws NullPointerException if {@code ingressPoints} or + * {@code egressPoint} is null. + * @throws IllegalArgumentException if the size of {@code ingressPoints} is + * not more than 1 + */ + private MultiPointToSinglePointIntent(ApplicationId appId, + Key key, + TrafficSelector selector, + TrafficTreatment treatment, + Set ingressPoints, + ConnectPoint egressPoint, + List constraints, + int priority) { + super(appId, key, Collections.emptyList(), selector, treatment, constraints, + priority); + + checkNotNull(ingressPoints); + checkArgument(!ingressPoints.isEmpty(), "Ingress point set cannot be empty"); + checkNotNull(egressPoint); + checkArgument(!ingressPoints.contains(egressPoint), + "Set of ingresses should not contain egress (egress: %s)", egressPoint); + + this.ingressPoints = Sets.newHashSet(ingressPoints); + this.egressPoint = egressPoint; + } + + /** + * Constructor for serializer. + */ + protected MultiPointToSinglePointIntent() { + super(); + this.ingressPoints = null; + this.egressPoint = null; + } + + /** + * Returns a new multi point to single point intent builder. The application id, + * ingress points and egress point are required fields. If they are + * not set by calls to the appropriate methods, an exception will + * be thrown. + * + * @return single point to multi point builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder of a multi point to single point intent. + */ + public static final class Builder extends ConnectivityIntent.Builder { + Set ingressPoints; + ConnectPoint egressPoint; + + private Builder() { + // Hide constructor + } + + @Override + public Builder appId(ApplicationId appId) { + return (Builder) super.appId(appId); + } + + @Override + public Builder key(Key key) { + return (Builder) super.key(key); + } + + @Override + public Builder selector(TrafficSelector selector) { + return (Builder) super.selector(selector); + } + + @Override + public Builder treatment(TrafficTreatment treatment) { + return (Builder) super.treatment(treatment); + } + + @Override + public Builder constraints(List constraints) { + return (Builder) super.constraints(constraints); + } + + @Override + public Builder priority(int priority) { + return (Builder) super.priority(priority); + } + + /** + * Sets the ingress point of the single point to multi point intent + * that will be built. + * + * @param ingressPoints ingress connect points + * @return this builder + */ + public Builder ingressPoints(Set ingressPoints) { + this.ingressPoints = ImmutableSet.copyOf(ingressPoints); + return this; + } + + /** + * Sets the egress point of the multi point to single point intent + * that will be built. + * + * @param egressPoint egress connect point + * @return this builder + */ + public Builder egressPoint(ConnectPoint egressPoint) { + this.egressPoint = egressPoint; + return this; + } + + /** + * Builds a multi point to single point intent from the + * accumulated parameters. + * + * @return point to point intent + */ + public MultiPointToSinglePointIntent build() { + + return new MultiPointToSinglePointIntent( + appId, + key, + selector, + treatment, + ingressPoints, + egressPoint, + constraints, + priority + ); + } + } + + + /** + * Returns the set of ports on which ingress traffic should be connected to + * the egress port. + * + * @return set of ingress ports + */ + public Set ingressPoints() { + return ingressPoints; + } + + /** + * Returns the port on which the traffic should egress. + * + * @return egress port + */ + public ConnectPoint egressPoint() { + return egressPoint; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("id", id()) + .add("key", key()) + .add("appId", appId()) + .add("priority", priority()) + .add("resources", resources()) + .add("selector", selector()) + .add("treatment", treatment()) + .add("ingress", ingressPoints()) + .add("egress", egressPoint()) + .add("constraints", constraints()) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/OpticalCircuitIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/OpticalCircuitIntent.java new file mode 100644 index 00000000..1e515c8c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/OpticalCircuitIntent.java @@ -0,0 +1,219 @@ +/* + * 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.intent; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.OduCltPort; + +import java.util.Collections; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An optical layer intent for circuits between two OduClt ports. + * No traffic selector or traffic treatment are needed. + */ +@Beta +public class OpticalCircuitIntent extends Intent { + private final ConnectPoint src; + private final ConnectPoint dst; + private final OduCltPort.SignalType signalType; + private final boolean isBidirectional; + + /** + * Creates an optical circuit intent between the specified + * connection points. + * + * @param appId application identification + * @param key intent key + * @param src the source transponder port + * @param dst the destination transponder port + * @param signalType ODU signal type + * @param isBidirectional indicate if intent is bidirectional + * @param priority priority to use for flows from this intent + */ + protected OpticalCircuitIntent(ApplicationId appId, Key key, ConnectPoint src, ConnectPoint dst, + OduCltPort.SignalType signalType, boolean isBidirectional, int priority) { + super(appId, key, Collections.emptyList(), priority); + this.src = checkNotNull(src); + this.dst = checkNotNull(dst); + this.signalType = checkNotNull(signalType); + this.isBidirectional = isBidirectional; + } + + /** + * Returns a new optical circuit intent builder. + * + * @return host to host intent builder + */ + public static Builder builder() { + return new Builder(); + } + + + /** + * Builder for optical circuit intents. + */ + public static class Builder extends Intent.Builder { + private ConnectPoint src; + private ConnectPoint dst; + private OduCltPort.SignalType signalType; + private boolean isBidirectional; + + @Override + public Builder appId(ApplicationId appId) { + return (Builder) super.appId(appId); + } + + @Override + public Builder key(Key key) { + return (Builder) super.key(key); + } + + @Override + public Builder priority(int priority) { + return (Builder) super.priority(priority); + } + + /** + * Sets the source for the intent that will be built. + * + * @param src source to use for built intent + * @return this builder + */ + public Builder src(ConnectPoint src) { + this.src = src; + return this; + } + + /** + * Sets the destination for the intent that will be built. + * + * @param dst dest to use for built intent + * @return this builder + */ + public Builder dst(ConnectPoint dst) { + this.dst = dst; + return this; + } + + /** + * Sets the ODU signal type for the intent that will be built. + * + * @param signalType signal type to use for built intent + * @return this builder + */ + public Builder signalType(OduCltPort.SignalType signalType) { + this.signalType = signalType; + return this; + } + + /** + * Sets the directionality of the intent. + * + * @param isBidirectional true if bidirectional, false if unidirectional + * @return this builder + */ + public Builder bidirectional(boolean isBidirectional) { + this.isBidirectional = isBidirectional; + return this; + } + + /** + * Builds an optical circuit intent from the accumulated parameters. + * + * @return point to point intent + */ + public OpticalCircuitIntent build() { + + return new OpticalCircuitIntent( + appId, + key, + src, + dst, + signalType, + isBidirectional, + priority + ); + } + } + + /** + * Constructor for serializer. + */ + protected OpticalCircuitIntent() { + super(); + this.src = null; + this.dst = null; + this.signalType = null; + this.isBidirectional = false; + } + + /** + * Returns the source transponder port. + * + * @return source transponder port + */ + public ConnectPoint getSrc() { + return src; + } + + /** + * Returns the destination transponder port. + * + * @return source transponder port + */ + public ConnectPoint getDst() { + return dst; + } + + /** + * Returns the ODU signal type. + * + * @return ODU signal type + */ + public OduCltPort.SignalType getSignalType() { + return signalType; + } + + /** + * Returns the directionality of the intent. + * + * @return true if bidirectional, false if unidirectional + */ + public boolean isBidirectional() { + return isBidirectional; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("id", id()) + .add("key", key()) + .add("appId", appId()) + .add("priority", priority()) + .add("resources", resources()) + .add("src", src) + .add("dst", dst) + .add("signalType", signalType) + .add("isBidirectional", isBidirectional) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/OpticalConnectivityIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/OpticalConnectivityIntent.java new file mode 100644 index 00000000..aeb0255f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/OpticalConnectivityIntent.java @@ -0,0 +1,223 @@ +/* + * Copyright 2014-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.intent; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.OduSignalType; + +import java.util.Collections; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An optical layer intent for connectivity between two OCh ports. + * No traffic selector or traffic treatment are needed. + */ +@Beta +public final class OpticalConnectivityIntent extends Intent { + private final ConnectPoint src; + private final ConnectPoint dst; + private final OduSignalType signalType; + private final boolean isBidirectional; + + /** + * Creates an optical connectivity intent between the specified + * connection points. + * + * @param appId application identification + * @param key intent key + * @param src the source transponder port + * @param dst the destination transponder port + * @param signalType signal type + * @param isBidirectional indicates if intent is unidirectional + * @param priority priority to use for flows from this intent + */ + protected OpticalConnectivityIntent(ApplicationId appId, + Key key, + ConnectPoint src, + ConnectPoint dst, + OduSignalType signalType, + boolean isBidirectional, + int priority) { + super(appId, key, Collections.emptyList(), priority); + this.src = checkNotNull(src); + this.dst = checkNotNull(dst); + this.signalType = checkNotNull(signalType); + this.isBidirectional = isBidirectional; + } + + /** + * Returns a new optical connectivity intent builder. + * + * @return host to host intent builder + */ + public static Builder builder() { + return new Builder(); + } + + + /** + * Builder for optical connectivity intents. + */ + public static class Builder extends Intent.Builder { + private ConnectPoint src; + private ConnectPoint dst; + private OduSignalType signalType; + private boolean isBidirectional; + + @Override + public Builder appId(ApplicationId appId) { + return (Builder) super.appId(appId); + } + + @Override + public Builder key(Key key) { + return (Builder) super.key(key); + } + + @Override + public Builder priority(int priority) { + return (Builder) super.priority(priority); + } + + /** + * Sets the source for the intent that will be built. + * + * @param src source to use for built intent + * @return this builder + */ + public Builder src(ConnectPoint src) { + this.src = src; + return this; + } + + /** + * Sets the destination for the intent that will be built. + * + * @param dst dest to use for built intent + * @return this builder + */ + public Builder dst(ConnectPoint dst) { + this.dst = dst; + return this; + } + + /** + * Sets the ODU signal type for the intent that will be built. + * + * @param signalType ODU signal type + * @return this builder + */ + public Builder signalType(OduSignalType signalType) { + this.signalType = signalType; + return this; + } + + /** + * Sets the directionality of the intent. + * + * @param isBidirectional true if bidirectional, false if unidirectional + * @return this builder + */ + public Builder bidirectional(boolean isBidirectional) { + this.isBidirectional = isBidirectional; + return this; + } + + /** + * Builds an optical connectivity intent from the accumulated parameters. + * + * @return point to point intent + */ + public OpticalConnectivityIntent build() { + + return new OpticalConnectivityIntent( + appId, + key, + src, + dst, + signalType, + isBidirectional, + priority + ); + } + } + + /** + * Constructor for serializer. + */ + protected OpticalConnectivityIntent() { + super(); + this.src = null; + this.dst = null; + this.signalType = null; + this.isBidirectional = false; + } + + /** + * Returns the source transponder port. + * + * @return source transponder port + */ + public ConnectPoint getSrc() { + return src; + } + + /** + * Returns the destination transponder port. + * + * @return source transponder port + */ + public ConnectPoint getDst() { + return dst; + } + + /** + * Returns the ODU signal type. + * + * @return ODU signal type + */ + public OduSignalType getSignalType() { + return signalType; + } + + /** + * Returns the directionality of the intent. + * + * @return true if bidirectional, false if unidirectional + */ + public boolean isBidirectional() { + return isBidirectional; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("id", id()) + .add("key", key()) + .add("appId", appId()) + .add("priority", priority()) + .add("resources", resources()) + .add("src", src) + .add("dst", dst) + .add("signalType", signalType) + .add("isBidirectional", isBidirectional) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/OpticalPathIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/OpticalPathIntent.java new file mode 100644 index 00000000..5a5461cb --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/OpticalPathIntent.java @@ -0,0 +1,234 @@ +/* + * Copyright 2014-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.intent; + +import com.google.common.annotations.Beta; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.OchSignal; +import org.onosproject.net.OchSignalType; +import org.onosproject.net.Path; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableSet; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An optical layer intent with explicitly selected path. + */ +@Beta +public final class OpticalPathIntent extends Intent { + + private final ConnectPoint src; + private final ConnectPoint dst; + private final Path path; + private final OchSignal lambda; + private final OchSignalType signalType; + private final boolean isBidirectional; + + private OpticalPathIntent(ApplicationId appId, + Key key, + ConnectPoint src, + ConnectPoint dst, + Path path, + OchSignal lambda, + OchSignalType signalType, + boolean isBidirectional, + int priority) { + super(appId, key, ImmutableSet.copyOf(path.links()), priority); + this.src = checkNotNull(src); + this.dst = checkNotNull(dst); + this.path = checkNotNull(path); + this.lambda = checkNotNull(lambda); + this.signalType = checkNotNull(signalType); + this.isBidirectional = isBidirectional; + } + + protected OpticalPathIntent() { + this.src = null; + this.dst = null; + this.path = null; + this.lambda = null; + this.signalType = null; + this.isBidirectional = true; + } + + /** + * Returns a new optical connectivity intent builder. + * + * @return host to host intent builder + */ + public static Builder builder() { + return new Builder(); + } + + + /** + * Builder for optical path intents. + */ + public static class Builder extends Intent.Builder { + private ConnectPoint src; + private ConnectPoint dst; + private Path path; + private OchSignal lambda; + private OchSignalType signalType; + private boolean isBidirectional; + Key key; + + @Override + public Builder appId(ApplicationId appId) { + return (Builder) super.appId(appId); + } + + @Override + public Builder key(Key key) { + return (Builder) super.key(key); + } + + @Override + public Builder priority(int priority) { + return (Builder) super.priority(priority); + } + + /** + * Sets the source for the intent that will be built. + * + * @param src source to use for built intent + * @return this builder + */ + public Builder src(ConnectPoint src) { + this.src = src; + return this; + } + + /** + * Sets the destination for the intent that will be built. + * + * @param dst dest to use for built intent + * @return this builder + */ + public Builder dst(ConnectPoint dst) { + this.dst = dst; + return this; + } + + /** + * Sets the path for the intent that will be built. + * + * @param path path to use for built intent + * @return this builder + */ + public Builder path(Path path) { + this.path = path; + return this; + } + + /** + * Sets the optical channel (lambda) for the intent that will be built. + * + * @param lambda the optical channel + * @return this builder + */ + public Builder lambda(OchSignal lambda) { + this.lambda = lambda; + return this; + } + + /** + * Sets the optical signal type for the intent that will be built. + * + * @param signalType the optical signal type + * @return this builder + */ + public Builder signalType(OchSignalType signalType) { + this.signalType = signalType; + return this; + } + + /** + * Sets the intent's direction. + * + * @param isBidirectional indicates if intent is bidirectional + * @return this builder + */ + public Builder bidirectional(boolean isBidirectional) { + this.isBidirectional = isBidirectional; + return this; + } + + /** + * Builds an optical path intent from the accumulated parameters. + * + * @return optical path intent + */ + public OpticalPathIntent build() { + + return new OpticalPathIntent( + appId, + key, + src, + dst, + path, + lambda, + signalType, + isBidirectional, + priority + ); + } + } + + + public ConnectPoint src() { + return src; + } + + public ConnectPoint dst() { + return dst; + } + + public Path path() { + return path; + } + + public OchSignal lambda() { + return lambda; + } + + public OchSignalType signalType() { + return signalType; + } + + public boolean isBidirectional() { + return isBidirectional; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("id", id()) + .add("appId", appId()) + .add("key", key()) + .add("resources", resources()) + .add("ingressPort", src) + .add("egressPort", dst) + .add("path", path) + .add("lambda", lambda) + .add("signalType", signalType) + .add("isBidirectional", isBidirectional) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PartitionEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PartitionEvent.java new file mode 100644 index 00000000..c79a3818 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PartitionEvent.java @@ -0,0 +1,35 @@ +/* + * 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.intent; + +import com.google.common.annotations.Beta; +import org.onosproject.event.AbstractEvent; + +/** + * Partition event. + */ +//TODO change String into a proper object type +@Beta +public class PartitionEvent extends AbstractEvent { + + public enum Type { + LEADER_CHANGED + } + + public PartitionEvent(Type type, String partition) { + super(type, partition); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PartitionEventListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PartitionEventListener.java new file mode 100644 index 00000000..5f1da334 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PartitionEventListener.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.intent; + +import com.google.common.annotations.Beta; +import org.onosproject.event.EventListener; + +/** + * Entity capable of receiving device partition-related events. + */ +@Beta +public interface PartitionEventListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PartitionService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PartitionService.java new file mode 100644 index 00000000..02ccccac --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PartitionService.java @@ -0,0 +1,48 @@ +/* + * 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.intent; + +import com.google.common.annotations.Beta; +import org.onosproject.cluster.NodeId; +import org.onosproject.event.ListenerService; + +/** + * Service for interacting with the partition-to-instance assignments. + */ +@Beta +public interface PartitionService + extends ListenerService { + + /** + * Returns whether the given intent key is in a partition owned by this + * instance or not. + * + * @param intentKey intent key to query + * @return true if the key is owned by this instance, otherwise false + */ + boolean isMine(Key intentKey); + + /** + * Returns the leader for a particular key. + * + * @param intentKey intent key to query + * @return the leader node + */ + NodeId getLeader(Key intentKey); + + // TODO add API for rebalancing partitions + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PathIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PathIntent.java new file mode 100644 index 00000000..dffbabfe --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PathIntent.java @@ -0,0 +1,202 @@ +/* + * Copyright 2014-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.intent; + +import java.util.List; + +import com.google.common.annotations.Beta; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import com.google.common.base.MoreObjects; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Abstraction of explicitly path specified connectivity intent. + */ +@Beta +public class PathIntent extends ConnectivityIntent { + + private final Path path; + + /** + * Creates a new point-to-point intent with the supplied ingress/egress + * ports and using the specified explicit path. + * + * @param appId application identifier + * @param selector traffic selector + * @param treatment treatment + * @param path traversed links + * @param constraints optional list of constraints + * @param priority priority to use for the generated flows + * @throws NullPointerException {@code path} is null + */ + protected PathIntent(ApplicationId appId, + TrafficSelector selector, + TrafficTreatment treatment, + Path path, + List constraints, + int priority) { + super(appId, null, resources(path.links()), selector, treatment, constraints, + priority); + PathIntent.validate(path.links()); + this.path = path; + } + + /** + * Constructor for serializer. + */ + protected PathIntent() { + super(); + this.path = null; + } + + /** + * Returns a new host to host intent builder. + * + * @return host to host intent builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder of a host to host intent. + */ + public static class Builder extends ConnectivityIntent.Builder { + Path path; + + protected Builder() { + // Hide default constructor + } + + @Override + public Builder appId(ApplicationId appId) { + return (Builder) super.appId(appId); + } + + @Override + public Builder key(Key key) { + return (Builder) super.key(key); + } + + @Override + public Builder selector(TrafficSelector selector) { + return (Builder) super.selector(selector); + } + + @Override + public Builder treatment(TrafficTreatment treatment) { + return (Builder) super.treatment(treatment); + } + + @Override + public Builder constraints(List constraints) { + return (Builder) super.constraints(constraints); + } + + @Override + public Builder priority(int priority) { + return (Builder) super.priority(priority); + } + + /** + * Sets the path of the intent that will be built. + * + * @param path path for the intent + * @return this builder + */ + public Builder path(Path path) { + this.path = path; + return this; + } + + /** + * Builds a path intent from the accumulated parameters. + * + * @return point to point intent + */ + public PathIntent build() { + + return new PathIntent( + appId, + selector, + treatment, + path, + constraints, + priority + ); + } + } + + + + // NOTE: This methods takes linear time with the number of links. + /** + * Validates that source element ID and destination element ID of a link are + * different for the specified all links and that destination element ID of a link and source + * element ID of the next adjacent source element ID are same for the specified all links. + * + * @param links links to be validated + */ + public static void validate(List links) { + checkArgument(Iterables.all(links, new Predicate() { + @Override + public boolean apply(Link link) { + return !link.src().elementId().equals(link.dst().elementId()); + } + }), "element of src and dst in a link must be different: {}", links); + + boolean adjacentSame = true; + for (int i = 0; i < links.size() - 1; i++) { + if (!links.get(i).dst().elementId().equals(links.get(i + 1).src().elementId())) { + adjacentSame = false; + break; + } + } + checkArgument(adjacentSame, "adjacent links must share the same element: {}", links); + } + + /** + * Returns the links which the traffic goes along. + * + * @return traversed links + */ + public Path path() { + return path; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("id", id()) + .add("appId", appId()) + .add("priority", priority()) + .add("resources", resources()) + .add("selector", selector()) + .add("treatment", treatment()) + .add("constraints", constraints()) + .add("path", path) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PointToPointIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PointToPointIntent.java new file mode 100644 index 00000000..d3f7529d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/PointToPointIntent.java @@ -0,0 +1,215 @@ +/* + * Copyright 2014-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.intent; + +import java.util.Collections; +import java.util.List; + +import com.google.common.annotations.Beta; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import com.google.common.base.MoreObjects; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Abstraction of point-to-point connectivity. + */ +@Beta +public final class PointToPointIntent extends ConnectivityIntent { + + private final ConnectPoint ingressPoint; + private final ConnectPoint egressPoint; + + /** + * Returns a new point to point intent builder. The application id, + * ingress point and egress point are required fields. If they are + * not set by calls to the appropriate methods, an exception will + * be thrown. + * + * @return point to point builder + */ + public static PointToPointIntent.Builder builder() { + return new Builder(); + } + + /** + * Builder of a point to point intent. + */ + public static final class Builder extends ConnectivityIntent.Builder { + ConnectPoint ingressPoint; + ConnectPoint egressPoint; + + private Builder() { + // Hide constructor + } + + @Override + public Builder appId(ApplicationId appId) { + return (Builder) super.appId(appId); + } + + @Override + public Builder key(Key key) { + return (Builder) super.key(key); + } + + @Override + public Builder selector(TrafficSelector selector) { + return (Builder) super.selector(selector); + } + + @Override + public Builder treatment(TrafficTreatment treatment) { + return (Builder) super.treatment(treatment); + } + + @Override + public Builder constraints(List constraints) { + return (Builder) super.constraints(constraints); + } + + @Override + public Builder priority(int priority) { + return (Builder) super.priority(priority); + } + + /** + * Sets the ingress point of the point to point intent that will be built. + * + * @param ingressPoint ingress connect point + * @return this builder + */ + public Builder ingressPoint(ConnectPoint ingressPoint) { + this.ingressPoint = ingressPoint; + return this; + } + + /** + * Sets the egress point of the point to point intent that will be built. + * + * @param egressPoint egress connect point + * @return this builder + */ + public Builder egressPoint(ConnectPoint egressPoint) { + this.egressPoint = egressPoint; + return this; + } + + /** + * Builds a point to point intent from the accumulated parameters. + * + * @return point to point intent + */ + public PointToPointIntent build() { + + return new PointToPointIntent( + appId, + key, + selector, + treatment, + ingressPoint, + egressPoint, + constraints, + priority + ); + } + } + + + + /** + * Creates a new point-to-point intent with the supplied ingress/egress + * ports and constraints. + * + * @param appId application identifier + * @param key key of the intent + * @param selector traffic selector + * @param treatment treatment + * @param ingressPoint ingress port + * @param egressPoint egress port + * @param constraints optional list of constraints + * @param priority priority to use for flows generated by this intent + * @throws NullPointerException if {@code ingressPoint} or + * {@code egressPoints} or {@code appId} is null. + */ + private PointToPointIntent(ApplicationId appId, + Key key, + TrafficSelector selector, + TrafficTreatment treatment, + ConnectPoint ingressPoint, + ConnectPoint egressPoint, + List constraints, + int priority) { + super(appId, key, Collections.emptyList(), selector, treatment, constraints, + priority); + + checkArgument(!ingressPoint.equals(egressPoint), + "ingress and egress should be different (ingress: %s, egress: %s)", ingressPoint, egressPoint); + + this.ingressPoint = checkNotNull(ingressPoint); + this.egressPoint = checkNotNull(egressPoint); + } + + /** + * Constructor for serializer. + */ + protected PointToPointIntent() { + super(); + this.ingressPoint = null; + this.egressPoint = null; + } + + /** + * Returns the port on which the ingress traffic should be connected to + * the egress. + * + * @return ingress port + */ + public ConnectPoint ingressPoint() { + return ingressPoint; + } + + /** + * Returns the port on which the traffic should egress. + * + * @return egress port + */ + public ConnectPoint egressPoint() { + return egressPoint; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("id", id()) + .add("key", key()) + .add("appId", appId()) + .add("priority", priority()) + .add("resources", resources()) + .add("selector", selector()) + .add("treatment", treatment()) + .add("ingress", ingressPoint) + .add("egress", egressPoint) + .add("constraints", constraints()) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/SinglePointToMultiPointIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/SinglePointToMultiPointIntent.java new file mode 100644 index 00000000..de555cf0 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/SinglePointToMultiPointIntent.java @@ -0,0 +1,219 @@ +/* + * Copyright 2014-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.intent; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableSet; + +import org.onosproject.core.ApplicationId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import java.util.Collections; +import java.util.Set; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Abstraction of single source, multiple destination connectivity intent. + */ +@Beta +public final class SinglePointToMultiPointIntent extends ConnectivityIntent { + + private final ConnectPoint ingressPoint; + private final Set egressPoints; + + /** + * Creates a new single-to-multi point connectivity intent. + * + * @param appId application identifier + * @param key intent key + * @param selector traffic selector + * @param treatment treatment + * @param ingressPoint port on which traffic will ingress + * @param egressPoints set of ports on which traffic will egress + * @param constraints constraints to apply to the intent + * @param priority priority to use for flows generated by this intent + * @throws NullPointerException if {@code ingressPoint} or + * {@code egressPoints} is null + * @throws IllegalArgumentException if the size of {@code egressPoints} is + * not more than 1 + */ + private SinglePointToMultiPointIntent(ApplicationId appId, + Key key, + TrafficSelector selector, TrafficTreatment treatment, + ConnectPoint ingressPoint, Set egressPoints, + List constraints, + int priority) { + super(appId, key, Collections.emptyList(), selector, treatment, constraints, + priority); + checkNotNull(egressPoints); + checkNotNull(ingressPoint); + checkArgument(!egressPoints.isEmpty(), "Egress point set cannot be empty"); + checkArgument(!egressPoints.contains(ingressPoint), + "Set of egresses should not contain ingress (ingress: %s)", ingressPoint); + + this.ingressPoint = checkNotNull(ingressPoint); + this.egressPoints = egressPoints; + } + + /** + * Returns a new single point to multi point intent builder. The application id, + * ingress point and egress points are required fields. If they are + * not set by calls to the appropriate methods, an exception will + * be thrown. + * + * @return single point to multi point builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder of a single point to multi point intent. + */ + public static final class Builder extends ConnectivityIntent.Builder { + ConnectPoint ingressPoint; + Set egressPoints; + + private Builder() { + // Hide constructor + } + + @Override + public Builder appId(ApplicationId appId) { + return (Builder) super.appId(appId); + } + + @Override + public Builder key(Key key) { + return (Builder) super.key(key); + } + + @Override + public Builder selector(TrafficSelector selector) { + return (Builder) super.selector(selector); + } + + @Override + public Builder treatment(TrafficTreatment treatment) { + return (Builder) super.treatment(treatment); + } + + @Override + public Builder constraints(List constraints) { + return (Builder) super.constraints(constraints); + } + + @Override + public Builder priority(int priority) { + return (Builder) super.priority(priority); + } + + /** + * Sets the ingress point of the single point to multi point intent + * that will be built. + * + * @param ingressPoint ingress connect point + * @return this builder + */ + public Builder ingressPoint(ConnectPoint ingressPoint) { + this.ingressPoint = ingressPoint; + return this; + } + + /** + * Sets the egress points of the single point to multi point intent + * that will be built. + * + * @param egressPoints egress connect points + * @return this builder + */ + public Builder egressPoints(Set egressPoints) { + this.egressPoints = ImmutableSet.copyOf(egressPoints); + return this; + } + + /** + * Builds a single point to multi point intent from the + * accumulated parameters. + * + * @return point to point intent + */ + public SinglePointToMultiPointIntent build() { + + return new SinglePointToMultiPointIntent( + appId, + key, + selector, + treatment, + ingressPoint, + egressPoints, + constraints, + priority + ); + } + } + + /** + * Constructor for serializer. + */ + protected SinglePointToMultiPointIntent() { + super(); + this.ingressPoint = null; + this.egressPoints = null; + } + + /** + * Returns the port on which the ingress traffic should be connected to the + * egress. + * + * @return ingress port + */ + public ConnectPoint ingressPoint() { + return ingressPoint; + } + + /** + * Returns the set of ports on which the traffic should egress. + * + * @return set of egress ports + */ + public Set egressPoints() { + return egressPoints; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("id", id()) + .add("key", key()) + .add("appId", appId()) + .add("priority", priority()) + .add("resources", resources()) + .add("selector", selector()) + .add("treatment", treatment()) + .add("ingress", ingressPoint) + .add("egress", egressPoints) + .add("constraints", constraints()) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/TwoWayP2PIntent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/TwoWayP2PIntent.java new file mode 100644 index 00000000..b9f126f4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/TwoWayP2PIntent.java @@ -0,0 +1,195 @@ +/* + * 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.intent; + +import java.util.Collections; +import java.util.List; + +import com.google.common.annotations.Beta; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import com.google.common.base.MoreObjects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Abstraction of bidirectional connectivity between two points in the network. + */ +@Beta +public final class TwoWayP2PIntent extends ConnectivityIntent { + + private final ConnectPoint one; + private final ConnectPoint two; + + + /** + * Creates a new host-to-host intent with the supplied host pair. + * + * @param appId application identifier + * @param key intent key + * @param one first host + * @param two second host + * @param selector action + * @param treatment ingress port + * @param constraints optional prioritized list of path selection constraints + * @param priority priority to use for flows generated by this intent + * @throws NullPointerException if {@code one} or {@code two} is null. + */ + private TwoWayP2PIntent(ApplicationId appId, Key key, + ConnectPoint one, ConnectPoint two, + TrafficSelector selector, + TrafficTreatment treatment, + List constraints, + int priority) { + super(appId, key, Collections.emptyList(), selector, treatment, constraints, + priority); + + // TODO: consider whether the case one and two are same is allowed + this.one = checkNotNull(one); + this.two = checkNotNull(two); + + } + + /** + * Returns a new two way intent builder. + * + * @return two way intent builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder of a point to point intent. + */ + public static final class Builder extends ConnectivityIntent.Builder { + ConnectPoint one; + ConnectPoint two; + + private Builder() { + // Hide constructor + } + + @Override + public Builder appId(ApplicationId appId) { + return (Builder) super.appId(appId); + } + + @Override + public Builder key(Key key) { + return (Builder) super.key(key); + } + + @Override + public Builder selector(TrafficSelector selector) { + return (Builder) super.selector(selector); + } + + @Override + public Builder treatment(TrafficTreatment treatment) { + return (Builder) super.treatment(treatment); + } + + @Override + public Builder constraints(List constraints) { + return (Builder) super.constraints(constraints); + } + + @Override + public Builder priority(int priority) { + return (Builder) super.priority(priority); + } + + /** + * Sets the first connection point of the two way intent that will be built. + * + * @param one first connect point + * @return this builder + */ + public Builder one(ConnectPoint one) { + this.one = one; + return this; + } + + /** + * Sets the second connection point of the two way intent that will be built. + * + * @param two second connect point + * @return this builder + */ + public Builder two(ConnectPoint two) { + this.two = two; + return this; + } + + /** + * Builds a point to point intent from the accumulated parameters. + * + * @return point to point intent + */ + public TwoWayP2PIntent build() { + + return new TwoWayP2PIntent( + appId, + key, + one, + two, + selector, + treatment, + constraints, + priority + ); + } + } + + /** + * Returns identifier of the first host. + * + * @return first host identifier + */ + public ConnectPoint one() { + return one; + } + + /** + * Returns identifier of the second host. + * + * @return second host identifier + */ + public ConnectPoint two() { + return two; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("id", id()) + .add("key", key()) + .add("appId", appId()) + .add("priority", priority()) + .add("resources", resources()) + .add("selector", selector()) + .add("treatment", treatment()) + .add("constraints", constraints()) + .add("one", one) + .add("two", two) + .toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/AnnotationConstraint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/AnnotationConstraint.java new file mode 100644 index 00000000..f5439efd --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/AnnotationConstraint.java @@ -0,0 +1,113 @@ +/* + * Copyright 2014 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.intent.constraint; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; +import org.onosproject.net.Link; +import org.onosproject.net.resource.link.LinkResourceService; + +import java.util.Objects; + +import static org.onosproject.net.AnnotationKeys.getAnnotatedValue; + +/** + * Constraint that evaluates an arbitrary link annotated value is under the specified threshold. + */ +@Beta +public class AnnotationConstraint extends BooleanConstraint { + + private final String key; + private final double threshold; + + /** + * Creates a new constraint to keep the value for the specified key + * of link annotation under the threshold. + * + * @param key key of link annotation + * @param threshold threshold value of the specified link annotation + */ + public AnnotationConstraint(String key, double threshold) { + this.key = key; + this.threshold = threshold; + } + + // Constructor for serialization + private AnnotationConstraint() { + this.key = ""; + this.threshold = 0; + } + + /** + * Returns the key of link annotation this constraint designates. + * @return key of link annotation + */ + public String key() { + return key; + } + + /** + * Returns the threshold this constraint ensures as link annotated value. + * + * @return threshold as link annotated value + */ + public double threshold() { + return threshold; + } + + @Override + public boolean isValid(Link link, LinkResourceService resourceService) { + double value = getAnnotatedValue(link, key); + + return value <= threshold; + } + + @Override + public double cost(Link link, LinkResourceService resourceService) { + if (isValid(link, resourceService)) { + return getAnnotatedValue(link, key); + } else { + return -1; + } + } + + @Override + public int hashCode() { + return Objects.hash(key, threshold); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof AnnotationConstraint)) { + return false; + } + + final AnnotationConstraint other = (AnnotationConstraint) obj; + return Objects.equals(this.key, other.key) && Objects.equals(this.threshold, other.threshold); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("key", key) + .add("threshold", threshold) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/AsymmetricPathConstraint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/AsymmetricPathConstraint.java new file mode 100644 index 00000000..e0f8614c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/AsymmetricPathConstraint.java @@ -0,0 +1,64 @@ +/* + * Copyright 2014 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.intent.constraint; + +import com.google.common.annotations.Beta; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.resource.link.LinkResourceService; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Constraint that serves as a request for asymmetric bi-directional path. + */ +@Beta +public class AsymmetricPathConstraint implements Constraint { + + @Override + public double cost(Link link, LinkResourceService resourceService) { + return 1; + } + + @Override + public boolean validate(Path path, LinkResourceService resourceService) { + return true; + } + + @Override + public int hashCode() { + return Objects.hashCode(true); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + return true; + } + + @Override + public String toString() { + return toStringHelper(this).toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BandwidthConstraint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BandwidthConstraint.java new file mode 100644 index 00000000..43b8e4b1 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BandwidthConstraint.java @@ -0,0 +1,96 @@ +/* + * Copyright 2014 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.intent.constraint; + +import com.google.common.annotations.Beta; +import org.onosproject.net.Link; +import org.onosproject.net.resource.link.BandwidthResource; +import org.onosproject.net.resource.link.BandwidthResourceRequest; +import org.onosproject.net.resource.link.LinkResourceService; +import org.onosproject.net.resource.ResourceRequest; +import org.onosproject.net.resource.ResourceType; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Constraint that evaluates links based on available bandwidths. + */ +@Beta +public class BandwidthConstraint extends BooleanConstraint { + + private final BandwidthResource bandwidth; + + /** + * Creates a new bandwidth constraint. + * + * @param bandwidth required bandwidth + */ + public BandwidthConstraint(BandwidthResource bandwidth) { + this.bandwidth = checkNotNull(bandwidth, "Bandwidth cannot be null"); + } + + // Constructor for serialization + private BandwidthConstraint() { + this.bandwidth = null; + } + + @Override + public boolean isValid(Link link, LinkResourceService resourceService) { + for (ResourceRequest request : resourceService.getAvailableResources(link)) { + if (request.type() == ResourceType.BANDWIDTH) { + BandwidthResourceRequest brr = (BandwidthResourceRequest) request; + if (brr.bandwidth().toDouble() >= bandwidth.toDouble()) { + return true; + } + } + } + return false; + } + + /** + * Returns the bandwidth required by this constraint. + * + * @return required bandwidth + */ + public BandwidthResource bandwidth() { + return bandwidth; + } + + @Override + public int hashCode() { + return Objects.hash(bandwidth); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final BandwidthConstraint other = (BandwidthConstraint) obj; + return Objects.equals(this.bandwidth, other.bandwidth); + } + + @Override + public String toString() { + return toStringHelper(this).add("bandwidth", bandwidth).toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BooleanConstraint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BooleanConstraint.java new file mode 100644 index 00000000..f1d4ad9f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/BooleanConstraint.java @@ -0,0 +1,64 @@ +/* + * Copyright 2014 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.intent.constraint; + +import com.google.common.annotations.Beta; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.resource.link.LinkResourceService; + +/** + * Abstract base class for various constraints that evaluate link viability + * in a yes/no fashion. + */ +@Beta +public abstract class BooleanConstraint implements Constraint { + + /** + * Returns true if the specified link satisfies the constraint. + * + * @param link link to be validated + * @param resourceService resource service for checking available link resources + * @return true if link is viable + */ + public abstract boolean isValid(Link link, LinkResourceService resourceService); + + /** + * {@inheritDoc} + * + * Negative return value means the specified link does not satisfy this constraint. + * + * @param link {@inheritDoc} + * @param resourceService {@inheritDoc} + * @return {@inheritDoc} + */ + @Override + public double cost(Link link, LinkResourceService resourceService) { + return isValid(link, resourceService) ? +1 : -1; + } + + @Override + public boolean validate(Path path, LinkResourceService resourceService) { + for (Link link : path.links()) { + if (!isValid(link, resourceService)) { + return false; + } + } + return true; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/LambdaConstraint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/LambdaConstraint.java new file mode 100644 index 00000000..9dd813b2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/LambdaConstraint.java @@ -0,0 +1,91 @@ +/* + * Copyright 2014 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.intent.constraint; + +import com.google.common.annotations.Beta; +import org.onosproject.net.Link; +import org.onosproject.net.resource.link.LambdaResource; +import org.onosproject.net.resource.link.LinkResourceService; +import org.onosproject.net.resource.ResourceRequest; +import org.onosproject.net.resource.ResourceType; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Constraint that evaluates links based on available lambda. + */ +@Beta +public class LambdaConstraint extends BooleanConstraint { + + private final LambdaResource lambda; + + /** + * Creates a new optical lambda constraint. + * + * @param lambda optional lambda to indicate a specific lambda + */ + public LambdaConstraint(LambdaResource lambda) { + this.lambda = lambda; + } + + // Constructor for serialization + private LambdaConstraint() { + this.lambda = null; + } + + @Override + public boolean isValid(Link link, LinkResourceService resourceService) { + for (ResourceRequest request : resourceService.getAvailableResources(link)) { + if (request.type() == ResourceType.LAMBDA) { + return true; + } + } + return false; + } + + /** + * Returns the lambda required by this constraint. + * + * @return required lambda + */ + public LambdaResource lambda() { + return lambda; + } + + @Override + public int hashCode() { + return Objects.hash(lambda); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final LambdaConstraint other = (LambdaConstraint) obj; + return Objects.equals(this.lambda, other.lambda); + } + + @Override + public String toString() { + return toStringHelper(this).add("lambda", lambda).toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/LatencyConstraint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/LatencyConstraint.java new file mode 100644 index 00000000..54eb4ea5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/LatencyConstraint.java @@ -0,0 +1,93 @@ +/* + * Copyright 2014 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.intent.constraint; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.resource.link.LinkResourceService; + +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.Objects; + +import static org.onosproject.net.AnnotationKeys.LATENCY; +import static org.onosproject.net.AnnotationKeys.getAnnotatedValue; + +/** + * Constraint that evaluates the latency through a path. + */ +@Beta +public class LatencyConstraint implements Constraint { + + private final Duration latency; + + /** + * Creates a new constraint to keep under specified latency through a path. + * @param latency latency to be kept + */ + public LatencyConstraint(Duration latency) { + this.latency = latency; + } + + // Constructor for serialization + private LatencyConstraint() { + this.latency = Duration.ZERO; + } + + public Duration latency() { + return latency; + } + + @Override + public double cost(Link link, LinkResourceService resourceService) { + return getAnnotatedValue(link, LATENCY); + } + + @Override + public boolean validate(Path path, LinkResourceService resourceService) { + double pathLatency = path.links().stream().mapToDouble(link -> cost(link, resourceService)).sum(); + return Duration.of((long) pathLatency, ChronoUnit.MICROS).compareTo(latency) <= 0; + } + + @Override + public int hashCode() { + return Objects.hash(latency); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof LatencyConstraint)) { + return false; + } + + final LatencyConstraint that = (LatencyConstraint) obj; + return Objects.equals(this.latency, that.latency); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("latency", latency) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/LinkTypeConstraint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/LinkTypeConstraint.java new file mode 100644 index 00000000..ffa4405b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/LinkTypeConstraint.java @@ -0,0 +1,108 @@ +/* + * Copyright 2014 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.intent.constraint; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableSet; +import org.onosproject.net.Link; +import org.onosproject.net.resource.link.LinkResourceService; + +import java.util.Objects; +import java.util.Set; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Constraint that evaluates links based on their type. + */ +@Beta +public class LinkTypeConstraint extends BooleanConstraint { + + private final Set types; + private final boolean isInclusive; + + /** + * Creates a new constraint for requesting connectivity using or avoiding + * the specified link types. + * + * @param inclusive indicates whether the given link types are to be + * permitted or avoided + * @param types link types + */ + public LinkTypeConstraint(boolean inclusive, Link.Type... types) { + checkNotNull(types, "Link types cannot be null"); + checkArgument(types.length > 0, "There must be more than one type"); + this.types = ImmutableSet.copyOf(types); + this.isInclusive = inclusive; + } + + // Constructor for serialization + private LinkTypeConstraint() { + this.types = null; + this.isInclusive = false; + } + + @Override + public boolean isValid(Link link, LinkResourceService resourceService) { + boolean contains = types.contains(link.type()); + return isInclusive ? contains : !contains; + } + + /** + * Returns the set of link types. + * + * @return set of link types + */ + public Set types() { + return types; + } + + /** + * Indicates if the constraint is inclusive or exclusive. + * + * @return true if inclusive + */ + public boolean isInclusive() { + return isInclusive; + } + + @Override + public int hashCode() { + return Objects.hash(types, isInclusive); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final LinkTypeConstraint other = (LinkTypeConstraint) obj; + return Objects.equals(this.types, other.types) && Objects.equals(this.isInclusive, other.isInclusive); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("inclusive", isInclusive) + .add("types", types) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/ObstacleConstraint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/ObstacleConstraint.java new file mode 100644 index 00000000..cb1e6b2b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/ObstacleConstraint.java @@ -0,0 +1,92 @@ +/* + * Copyright 2014-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.intent.constraint; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableSet; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.resource.link.LinkResourceService; + +import java.util.Collections; +import java.util.Objects; +import java.util.Set; + +/** + * Constraint that evaluates elements not passed through. + */ +@Beta +public class ObstacleConstraint extends BooleanConstraint { + + private final Set obstacles; + + /** + * Creates a new constraint that the specified device are not passed through. + * @param obstacles devices not to be passed + */ + public ObstacleConstraint(DeviceId... obstacles) { + this.obstacles = ImmutableSet.copyOf(obstacles); + } + + // Constructor for serialization + private ObstacleConstraint() { + this.obstacles = Collections.emptySet(); + } + + /** + * Returns the obstacle device ids. + * + * @return Set of obstacle device ids + */ + public Set obstacles() { + return obstacles; + } + + @Override + public boolean isValid(Link link, LinkResourceService resourceService) { + DeviceId src = link.src().deviceId(); + DeviceId dst = link.dst().deviceId(); + + return !(obstacles.contains(src) || obstacles.contains(dst)); + } + + @Override + public int hashCode() { + return Objects.hash(obstacles); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof ObstacleConstraint)) { + return false; + } + + final ObstacleConstraint that = (ObstacleConstraint) obj; + return Objects.equals(this.obstacles, that.obstacles); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("obstacles", obstacles) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/PartialFailureConstraint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/PartialFailureConstraint.java new file mode 100644 index 00000000..827859b1 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/PartialFailureConstraint.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.intent.constraint; + +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.intent.ConnectivityIntent; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.resource.link.LinkResourceService; + +/** + * A constraint that allows intents that can only be partially compiled + * (i.e. MultiPointToSinglePointIntent or SinglePointToMultiPointIntent) + * to be installed when some endpoints or paths are not found. + */ +public class PartialFailureConstraint implements Constraint { + @Override + public double cost(Link link, LinkResourceService resourceService) { + return 1; + } + + @Override + public boolean validate(Path path, LinkResourceService resourceService) { + return true; + } + + public static boolean intentAllowsPartialFailure(Intent intent) { + if (intent instanceof ConnectivityIntent) { + ConnectivityIntent connectivityIntent = (ConnectivityIntent) intent; + return connectivityIntent.constraints().stream() + .anyMatch(c -> c instanceof PartialFailureConstraint); + } + return false; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/WaypointConstraint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/WaypointConstraint.java new file mode 100644 index 00000000..1acf6dfe --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/WaypointConstraint.java @@ -0,0 +1,117 @@ +/* + * Copyright 2014 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.intent.constraint; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.resource.link.LinkResourceService; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Constraint that evaluates elements passed through in order. + */ +@Beta +public class WaypointConstraint implements Constraint { + + private final List waypoints; + + /** + * Creates a new waypoint constraint. + * + * @param waypoints waypoints + */ + public WaypointConstraint(DeviceId... waypoints) { + checkNotNull(waypoints, "waypoints cannot be null"); + checkArgument(waypoints.length > 0, "length of waypoints should be more than 0"); + this.waypoints = ImmutableList.copyOf(waypoints); + } + + // Constructor for serialization + private WaypointConstraint() { + this.waypoints = Collections.emptyList(); + } + + public List waypoints() { + return waypoints; + } + + @Override + public double cost(Link link, LinkResourceService resourceService) { + // Always consider the number of hops + return 1; + } + + @Override + public boolean validate(Path path, LinkResourceService resourceService) { + LinkedList waypoints = new LinkedList<>(this.waypoints); + DeviceId current = waypoints.poll(); + // This is safe because Path class ensures the number of links are more than 0 + Link firstLink = path.links().get(0); + if (firstLink.src().elementId().equals(current)) { + current = waypoints.poll(); + } + + for (Link link : path.links()) { + if (link.dst().elementId().equals(current)) { + current = waypoints.poll(); + // Empty waypoints means passing through all waypoints in the specified order + if (current == null) { + return true; + } + } + } + + return false; + } + + @Override + public int hashCode() { + return Objects.hash(waypoints); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof WaypointConstraint)) { + return false; + } + + final WaypointConstraint that = (WaypointConstraint) obj; + return Objects.equals(this.waypoints, that.waypoints); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("waypoints", waypoints) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/package-info.java new file mode 100644 index 00000000..60d8df16 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/constraint/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Definitions of constraints used to refine intent specifications. + */ +package org.onosproject.net.intent.constraint; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/package-info.java new file mode 100644 index 00000000..a86b3118 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/intent/package-info.java @@ -0,0 +1,83 @@ +/* + * Copyright 2014-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. + */ + +/** + * Set of abstractions for conveying high-level intents for treatment of + * selected network traffic by allowing applications to express the + * what rather than the how. This makes such instructions + * largely independent of topology and device specifics, thus allowing them to + * survive topology mutations. + *

+ * The controller core provides a suite of built-in intents and their compilers + * and installers. However, the intent framework is extensible in that it allows + * additional intents and their compilers or installers to be added + * dynamically at run-time. This allows others to enhance the initial arsenal of + * connectivity and policy-based intents available in base controller software. + *

+ *

+ * The following diagram depicts the state transition diagram for each top-level intent:
+ * ONOS intent states + *

+ *

+ * The controller core accepts the intent specifications and translates them, via a + * process referred to as intent compilation, to installable intents, which are + * essentially actionable operations on the network environment. + * These actions are carried out by intent installation process, which results + * in some changes to the environment, e.g. tunnel links being provisioned, + * flow rules being installed on the data-plane, optical lambdas being reserved. + *

+ *

+ * After an intent is submitted by an application, it will be sent immediately + * (but asynchronously) into a compiling phase, then to installing phase and if + * all goes according to plan into installed state. Once an application decides + * it no longer wishes the intent to hold, it can withdraw it. This describes + * the nominal flow. However, it may happen that some issue is encountered. + * For example, an application may ask for an objective that is not currently + * achievable, e.g. connectivity across to unconnected network segments. + * If this is the case, the compiling phase may fail to produce a set of + * installable intents and instead result in a failed compile. If this occurs, + * only a change in the environment can trigger a transition back to the + * compiling state. + *

+ *

+ * Similarly, an issue may be encountered during the installation phase in + * which case the framework will attempt to recompile the intent to see if an + * alternate approach is available. If so, the intent will be sent back to + * installing phase. Otherwise, it will be parked in the failed state. Another + * scenario that’s very likely to be encountered is where the intent is + * successfully compiled and installed, but due to some topology event, such + * as a downed or downgraded link, loss of throughput may occur or connectivity + * may be lost altogether, thus impacting the viability of a previously + * satisfied intent. If this occurs, the framework will attempt to recompile + * the intent, and if an alternate approach is available, its installation + * will be attempted. Otherwise, the original top-level intent will be parked + * in the failed state. + *

+ *

+ * Please note that all *ing states, depicted in orange, are transitional and + * are expected to last only a brief amount of time. The rest of the states + * are parking states where the intent may spent some time; except for the + * submitted state of course. There, the intent may pause, but only briefly, + * while the system determines where to perform the compilation or while it + * performs global recomputation/optimization across all prior intents. + *

+ *

+ * The figure below depicts the general interactions between different + * components of the intent subsystem.
+ * ONOS intent subsystem design + *

+ */ +package org.onosproject.net.intent; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/DefaultLinkDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/DefaultLinkDescription.java new file mode 100644 index 00000000..891eb65d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/DefaultLinkDescription.java @@ -0,0 +1,73 @@ +/* + * Copyright 2014 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.link; + +import com.google.common.base.MoreObjects; +import org.onosproject.net.AbstractDescription; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Link; +import org.onosproject.net.SparseAnnotations; + +/** + * Default implementation of immutable link description entity. + */ +public class DefaultLinkDescription extends AbstractDescription + implements LinkDescription { + + private final ConnectPoint src; + private final ConnectPoint dst; + private final Link.Type type; + + /** + * Creates a link description using the supplied information. + * + * @param src link source + * @param dst link destination + * @param type link type + * @param annotations optional key/value annotations + */ + public DefaultLinkDescription(ConnectPoint src, ConnectPoint dst, + Link.Type type, SparseAnnotations... annotations) { + super(annotations); + this.src = src; + this.dst = dst; + this.type = type; + } + + @Override + public ConnectPoint src() { + return src; + } + + @Override + public ConnectPoint dst() { + return dst; + } + + @Override + public Link.Type type() { + return type; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("src", src()) + .add("dst", dst()) + .add("type", type()).toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkAdminService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkAdminService.java new file mode 100644 index 00000000..a0b5e1e2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkAdminService.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014-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.link; + +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; + +/** + * Service for administering the inventory of infrastructure links. + */ +public interface LinkAdminService extends LinkService { + + /** + * Removes all infrastructure links leading to and from the + * specified connection point. + * + * @param connectPoint connection point + */ + void removeLinks(ConnectPoint connectPoint); + + /** + * Removes all infrastructure links leading to and from the + * specified device. + * + * @param deviceId device identifier + */ + void removeLinks(DeviceId deviceId); + + /** + * Removes all links between between the specified src and + * dst connection points. + * + * @param src link source + * @param dst link destination + */ + void removeLink(ConnectPoint src, ConnectPoint dst); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkDescription.java new file mode 100644 index 00000000..f85718b7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkDescription.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 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.link; + +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Description; +import org.onosproject.net.Link; + +/** + * Describes an infrastructure link. + */ +public interface LinkDescription extends Description { + + /** + * Returns the link source. + * + * @return links source + */ + ConnectPoint src(); + + /** + * Returns the link destination. + * + * @return links destination + */ + ConnectPoint dst(); + + /** + * Returns the link type. + * + * @return link type + */ + Link.Type type(); + + // Add further link attributes +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkEvent.java new file mode 100644 index 00000000..d87bce06 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkEvent.java @@ -0,0 +1,68 @@ +/* + * Copyright 2014 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.link; + +import org.onosproject.event.AbstractEvent; +import org.onosproject.net.Link; + +/** + * Describes infrastructure link event. + */ +public class LinkEvent extends AbstractEvent { + + /** + * Type of link events. + */ + public enum Type { + /** + * Signifies that a new link has been detected. + */ + LINK_ADDED, + + /** + * Signifies that a link has been updated or changed state. + */ + LINK_UPDATED, + + /** + * Signifies that a link has been removed. + */ + LINK_REMOVED + } + + /** + * Creates an event of a given type and for the specified link and the + * current time. + * + * @param type link event type + * @param link event link subject + */ + public LinkEvent(Type type, Link link) { + super(type, link); + } + + /** + * Creates an event of a given type and for the specified link and time. + * + * @param type link event type + * @param link event link subject + * @param time occurrence time + */ + public LinkEvent(Type type, Link link, long time) { + super(type, link, time); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkListener.java new file mode 100644 index 00000000..82f6bdb9 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkListener.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.link; + +import org.onosproject.event.EventListener; + +/** + * Entity capable of receiving infrastructure link related events. + */ +public interface LinkListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkProvider.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkProvider.java new file mode 100644 index 00000000..ed4348c7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkProvider.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 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.link; + +import org.onosproject.net.provider.Provider; + +/** + * Abstraction of an entity providing information about infrastructure links + * to the core. + */ +public interface LinkProvider extends Provider { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkProviderRegistry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkProviderRegistry.java new file mode 100644 index 00000000..57a05d93 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkProviderRegistry.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 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.link; + +import org.onosproject.net.provider.ProviderRegistry; + +/** + * Abstraction of an infrastructure link provider registry. + */ +public interface LinkProviderRegistry + extends ProviderRegistry { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkProviderService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkProviderService.java new file mode 100644 index 00000000..f5ef52a2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkProviderService.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014 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.link; + +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.provider.ProviderService; + +/** + * Means for injecting link information into the core. + */ +public interface LinkProviderService extends ProviderService { + + /** + * Signals that an infrastructure link has been detected. + * + * @param linkDescription link information + */ + void linkDetected(LinkDescription linkDescription); + + /** + * Signals that an infrastructure link has disappeared. + * + * @param linkDescription link information + */ + void linkVanished(LinkDescription linkDescription); + + /** + * Signals that infrastructure links associated with the specified + * connect point have vanished. + * + * @param connectPoint connect point + */ + void linksVanished(ConnectPoint connectPoint); + + /** + * Signals that infrastructure links associated with the specified + * device have vanished. + * + * @param deviceId device identifier + */ + void linksVanished(DeviceId deviceId); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkService.java new file mode 100644 index 00000000..c27e3110 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkService.java @@ -0,0 +1,116 @@ +/* + * Copyright 2014 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.link; + +import java.util.Set; + +import org.onosproject.event.ListenerService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; + +/** + * Service for interacting with the inventory of infrastructure links. + */ +public interface LinkService + extends ListenerService { + + /** + * Returns the count of all known infrastructure links. + * + * @return number of infrastructure links + */ + int getLinkCount(); + + /** + * Returns a collection of all known infrastructure links. + * + * @return all infrastructure links + */ + Iterable getLinks(); + + /** + * Returns a collection of all active infrastructure links. + * + * @return all infrastructure links + */ + Iterable getActiveLinks(); + + /** + * Returns set of all infrastructure links leading to and from the + * specified device. + * + * @param deviceId device identifier + * @return set of device links + */ + Set getDeviceLinks(DeviceId deviceId); + + /** + * Returns set of all infrastructure links leading from the specified device. + * + * @param deviceId device identifier + * @return set of device egress links + */ + Set getDeviceEgressLinks(DeviceId deviceId); + + /** + * Returns set of all infrastructure links leading to the specified device. + * + * @param deviceId device identifier + * @return set of device ingress links + */ + Set getDeviceIngressLinks(DeviceId deviceId); + + /** + * Returns set of all infrastructure links leading to and from the + * specified connection point. + * + * @param connectPoint connection point + * @return set of links + */ + Set getLinks(ConnectPoint connectPoint); + + /** + * Returns set of all infrastructure links leading from the specified + * connection point. + * + * @param connectPoint connection point + * @return set of device egress links + */ + Set getEgressLinks(ConnectPoint connectPoint); + + /** + * Returns set of all infrastructure links leading to the specified + * connection point. + * + * @param connectPoint connection point + * @return set of device ingress links + */ + Set getIngressLinks(ConnectPoint connectPoint); + + // FIXME: I don't think this makes sense; discuss and remove or adjust return + // to be a Set or add Link.Type parameter + /** + * Returns the infrastructure links between the specified source + * and destination connection points. + * + * @param src source connection point + * @param dst destination connection point + * @return link from source to destination; null if none found + */ + Link getLink(ConnectPoint src, ConnectPoint dst); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkStore.java new file mode 100644 index 00000000..04c8773b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkStore.java @@ -0,0 +1,117 @@ +/* + * Copyright 2014 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.link; + +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.store.Store; + +import java.util.Set; + +/** + * Manages inventory of infrastructure links; not intended for direct use. + */ +public interface LinkStore extends Store { + + /** + * Returns the number of links in the store. + * + * @return number of links + */ + int getLinkCount(); + + /** + * Returns an iterable collection of all links in the inventory. + * + * @return collection of all links + */ + Iterable getLinks(); + + /** + * Returns all links egressing from the specified device. + * + * @param deviceId device identifier + * @return set of device links + */ + Set getDeviceEgressLinks(DeviceId deviceId); + + /** + * Returns all links ingressing from the specified device. + * + * @param deviceId device identifier + * @return set of device links + */ + Set getDeviceIngressLinks(DeviceId deviceId); + + /** + * Returns the link between the two end-points. + * + * @param src source connection point + * @param dst destination connection point + * @return link or null if one not found between the end-points + */ + Link getLink(ConnectPoint src, ConnectPoint dst); + + /** + * Returns all links egressing from the specified connection point. + * + * @param src source connection point + * @return set of connection point links + */ + Set getEgressLinks(ConnectPoint src); + + /** + * Returns all links ingressing to the specified connection point. + * + * @param dst destination connection point + * @return set of connection point links + */ + Set getIngressLinks(ConnectPoint dst); + + /** + * Creates a new link, or updates an existing one, based on the given + * information. + * + * @param providerId provider identity + * @param linkDescription link description + * @return create or update link event, or null if no change resulted + */ + LinkEvent createOrUpdateLink(ProviderId providerId, + LinkDescription linkDescription); + + /** + * Removes the link, or marks it as inactive if the link is durable, + * based on the specified information. + * + * @param src link source + * @param dst link destination + * @return remove or update link event, or null if no change resulted + */ + LinkEvent removeOrDownLink(ConnectPoint src, ConnectPoint dst); + + /** + * Removes the link based on the specified information. + * + * @param src link source + * @param dst link destination + * @return remove link event, or null if no change resulted + */ + LinkEvent removeLink(ConnectPoint src, ConnectPoint dst); + + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkStoreDelegate.java new file mode 100644 index 00000000..1f66dd49 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/LinkStoreDelegate.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.link; + +import org.onosproject.store.StoreDelegate; + +/** + * Infrastructure link store delegate abstraction. + */ +public interface LinkStoreDelegate extends StoreDelegate { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/package-info.java new file mode 100644 index 00000000..57aa5fa2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/link/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Infrastructure link model & related services API definitions. + */ +package org.onosproject.net.link; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/Band.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/Band.java new file mode 100644 index 00000000..2bfafad2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/Band.java @@ -0,0 +1,133 @@ +/* + * 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; + +/** + * Represents a band used within a meter. + */ +public interface Band { + + /** + * Specifies the type of band. + */ + enum Type { + /** + * Simple rate limiter which drops packets + * when the rate is exceeded. + */ + DROP, + + /** + * defines a simple DiffServ policer that remark + * the drop precedence of the DSCP field in the + * IP header of the packets that exceed the band + * rate value. + */ + REMARK + } + + /** + * The rate at which this meter applies. + * + * @return the long value of the rate + */ + long rate(); + + /** + * The burst size at which the meter applies. + * + * @return the long value of the size + */ + long burst(); + + /** + * Only meaningful in the case of a REMARK band type. + * indicates by which amount the drop precedence of + * the packet should be increase if the band is exceeded. + * + * @return a short value + */ + short dropPrecedence(); + + /** + * Signals the type of band to create. + * + * @return a band type + */ + Type type(); + + /** + * Returns the packets seen by this band. + * + * @return a long value + */ + long packets(); + + /** + * Return the bytes seen by this band. + * + * @return a byte counter + */ + long bytes(); + + interface Builder { + + /** + * Assigns a rate to this band. The units for this rate + * are defined in the encapsulating meter. + * + * @param rate a long value + * @return this + */ + Builder withRate(long rate); + + /** + * Assigns a burst size to this band. Only meaningful if + * the encapsulating meter is of burst type. + * + * @param burstSize a long value. + * @return this + */ + Builder burstSize(long burstSize); + + /** + * Assigns the drop precedence for this band. Only meaningful if + * the band is of REMARK type. + * + * @param prec a short value + * @return this + */ + Builder dropPrecedence(short prec); + + /** + * Assigns the @See Type of this band. + * + * @param type a band type + * @return this + */ + Builder ofType(Type type); + + /** + * Builds the band. + * + * @return a band + */ + Band build(); + + } + + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/BandEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/BandEntry.java new file mode 100644 index 00000000..03145e91 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/BandEntry.java @@ -0,0 +1,37 @@ +/* + * 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; + +/** + * Represents a stored band. + */ +public interface BandEntry extends Band { + + /** + * Sets the number of packets seen by this band. + * + * @param packets a packet count + */ + void setPackets(long packets); + + /** + * Sets the number of bytes seen by this band. + * + * @param bytes a byte counter + */ + void setBytes(long bytes); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultBand.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultBand.java new file mode 100644 index 00000000..58a24766 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultBand.java @@ -0,0 +1,136 @@ +/* + * 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 static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; + +/** + * A default implementation for a Band. + */ +public final class DefaultBand implements Band, BandEntry { + + private final Type type; + private final long rate; + //TODO: should be made optional + private final Long burstSize; + private final Short prec; + private long packets; + private long bytes; + + public DefaultBand(Type type, long rate, + Long burstSize, Short prec) { + this.type = type; + this.rate = rate; + this.burstSize = burstSize; + this.prec = prec; + } + + @Override + public long rate() { + return rate; + } + + @Override + public long burst() { + return burstSize; + } + + @Override + public short dropPrecedence() { + return prec; + } + + @Override + public Type type() { + return type; + } + + @Override + public long packets() { + return packets; + } + + @Override + public long bytes() { + return bytes; + } + + @Override + public void setPackets(long packets) { + this.packets = packets; + } + + @Override + public void setBytes(long bytes) { + this.bytes = bytes; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("rate", rate) + .add("burst-size", burstSize) + .add("type", type) + .add("drop-precedence", prec).toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder implements Band.Builder { + + private long rate; + private Long burstSize; + private Short prec; + private Type type; + + @Override + public Band.Builder withRate(long rate) { + this.rate = rate; + return this; + } + + @Override + public Band.Builder burstSize(long burstSize) { + this.burstSize = burstSize; + return this; + } + + @Override + public Band.Builder dropPrecedence(short prec) { + this.prec = prec; + return this; + } + + @Override + public Band.Builder ofType(Type type) { + this.type = type; + return this; + } + + @Override + public DefaultBand build() { + checkArgument(type != Type.REMARK && prec == null, + "Only REMARK bands can have a precendence."); + + return new DefaultBand(type, rate, burstSize, prec); + } + + + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeter.java new file mode 100644 index 00000000..f7d6210d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeter.java @@ -0,0 +1,233 @@ +/* + * 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 com.google.common.collect.ImmutableSet; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.DeviceId; + +import java.util.Collection; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A default implementation of a meter. + */ +public final class DefaultMeter implements Meter, MeterEntry { + + + private final MeterId id; + private final ApplicationId appId; + private final Unit unit; + private final boolean burst; + private final Collection bands; + private final DeviceId deviceId; + + private MeterState state; + private long life; + private long refCount; + private long packets; + private long bytes; + + private DefaultMeter(DeviceId deviceId, MeterId id, ApplicationId appId, + Unit unit, boolean burst, + Collection bands) { + this.deviceId = deviceId; + this.id = id; + this.appId = appId; + this.unit = unit; + this.burst = burst; + this.bands = bands; + } + + @Override + public DeviceId deviceId() { + return deviceId; + } + + @Override + public MeterId id() { + return id; + } + + @Override + public ApplicationId appId() { + return appId; + } + + @Override + public Unit unit() { + return unit; + } + + @Override + public boolean isBurst() { + return burst; + } + + @Override + public Collection bands() { + return bands; + } + + @Override + public MeterState state() { + return state; + } + + @Override + public long life() { + return life; + } + + @Override + public long referenceCount() { + return refCount; + } + + @Override + public long packetsSeen() { + return packets; + } + + @Override + public long bytesSeen() { + return bytes; + } + + public static Builder builder() { + return new Builder(); + } + + @Override + public void setState(MeterState state) { + this.state = state; + } + + @Override + public void setLife(long life) { + this.life = life; + } + + @Override + public void setReferenceCount(long count) { + this.refCount = count; + } + + @Override + public void setProcessedPackets(long packets) { + this.packets = packets; + } + + @Override + public void setProcessedBytes(long bytes) { + this.bytes = bytes; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("device", deviceId) + .add("id", id) + .add("appId", appId.name()) + .add("unit", unit) + .add("isBurst", burst) + .add("state", state) + .add("bands", bands).toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DefaultMeter that = (DefaultMeter) o; + return Objects.equal(id, that.id) && + Objects.equal(appId, that.appId) && + Objects.equal(unit, that.unit) && + Objects.equal(deviceId, that.deviceId); + } + + @Override + public int hashCode() { + return Objects.hashCode(id, appId, unit, deviceId); + } + + public static final class Builder implements Meter.Builder { + + private MeterId id; + private ApplicationId appId; + private Unit unit = Unit.KB_PER_SEC; + private boolean burst = false; + private Collection bands; + private DeviceId deviceId; + + + @Override + public Meter.Builder forDevice(DeviceId deviceId) { + this.deviceId = deviceId; + return this; + } + + @Override + public Meter.Builder withId(MeterId id) { + this.id = id; + return this; + } + + @Override + public Meter.Builder fromApp(ApplicationId appId) { + this.appId = appId; + return this; + } + + @Override + public Meter.Builder withUnit(Unit unit) { + this.unit = unit; + return this; + } + + @Override + public Meter.Builder burst() { + this.burst = true; + return this; + } + + @Override + public Meter.Builder withBands(Collection bands) { + this.bands = ImmutableSet.copyOf(bands); + return this; + } + + @Override + public DefaultMeter build() { + checkNotNull(deviceId, "Must specify a device"); + checkNotNull(bands, "Must have bands."); + checkArgument(bands.size() > 0, "Must have at least one band."); + checkNotNull(appId, "Must have an application id"); + checkNotNull(id, "Must specify a meter id"); + return new DefaultMeter(deviceId, id, appId, unit, burst, bands); + } + + + } +} 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 new file mode 100644 index 00000000..94cada47 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/DefaultMeterRequest.java @@ -0,0 +1,171 @@ +/* + * 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.collect.ImmutableSet; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.DeviceId; + +import java.util.Collection; +import java.util.Optional; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A default implementation of a meter. + */ +public final class DefaultMeterRequest implements MeterRequest { + + + + private final ApplicationId appId; + private final Meter.Unit unit; + private final boolean burst; + private final Collection bands; + private final DeviceId deviceId; + private final Optional context; + private final Type op; + + private DefaultMeterRequest(DeviceId deviceId, ApplicationId appId, + Meter.Unit unit, boolean burst, + Collection bands, MeterContext context, Type op) { + this.deviceId = deviceId; + this.appId = appId; + this.unit = unit; + this.burst = burst; + this.bands = bands; + this.context = Optional.ofNullable(context); + this.op = op; + } + + @Override + public DeviceId deviceId() { + return deviceId; + } + + @Override + public ApplicationId appId() { + return appId; + } + + @Override + public Meter.Unit unit() { + return unit; + } + + @Override + public boolean isBurst() { + return burst; + } + + @Override + public Collection bands() { + return bands; + } + + @Override + public Optional context() { + return context; + } + + + + public static Builder builder() { + return new Builder(); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("device", deviceId) + .add("appId", appId.name()) + .add("unit", unit) + .add("isBurst", burst) + .add("bands", bands).toString(); + } + + public static final class Builder implements MeterRequest.Builder { + + private ApplicationId appId; + private Meter.Unit unit = Meter.Unit.KB_PER_SEC; + private boolean burst = false; + private Collection bands; + private DeviceId deviceId; + private MeterContext context; + + + @Override + public MeterRequest.Builder forDevice(DeviceId deviceId) { + this.deviceId = deviceId; + return this; + } + + @Override + public MeterRequest.Builder fromApp(ApplicationId appId) { + this.appId = appId; + return this; + } + + @Override + public MeterRequest.Builder withUnit(Meter.Unit unit) { + this.unit = unit; + return this; + } + + @Override + public MeterRequest.Builder burst() { + this.burst = true; + return this; + } + + @Override + public MeterRequest.Builder withBands(Collection bands) { + this.bands = ImmutableSet.copyOf(bands); + return this; + } + + @Override + public MeterRequest.Builder withContext(MeterContext context) { + this.context = context; + return this; + } + + @Override + public MeterRequest add() { + validate(); + return new DefaultMeterRequest(deviceId, appId, unit, burst, bands, + context, Type.ADD); + } + + @Override + public MeterRequest remove() { + validate(); + return new DefaultMeterRequest(deviceId, appId, unit, burst, bands, + context, Type.REMOVE); + } + + private void validate() { + checkNotNull(deviceId, "Must specify a device"); + checkNotNull(bands, "Must have bands."); + checkArgument(bands.size() > 0, "Must have at least one band."); + checkNotNull(appId, "Must have an application id"); + } + + + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/Meter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/Meter.java new file mode 100644 index 00000000..98ebc350 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/Meter.java @@ -0,0 +1,179 @@ +/* + * 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 org.onosproject.core.ApplicationId; +import org.onosproject.net.DeviceId; + +import java.util.Collection; + +/** + * Represents a generalized meter to be deployed on a device. + */ +public interface Meter { + + enum Unit { + /** + * Packets per second. + */ + PKTS_PER_SEC, + + /** + * Kilo bits per second. + */ + KB_PER_SEC + } + + /** + * The target device for this meter. + * + * @return a device id + */ + DeviceId deviceId(); + + /** + * This meters id. + * + * @return a meter id + */ + MeterId id(); + + /** + * The id of the application which created this meter. + * + * @return an application id + */ + ApplicationId appId(); + + /** + * The unit used within this meter. + * + * @return the unit + */ + Unit unit(); + + /** + * Signals whether this meter applies to bursts only. + * + * @return a boolean + */ + boolean isBurst(); + + /** + * The collection of bands to apply on the dataplane. + * + * @return a collection of bands. + */ + Collection bands(); + + /** + * Fetches the state of this meter. + * + * @return a meter state + */ + MeterState state(); + + /** + * The lifetime in seconds of this meter. + * + * @return number of seconds + */ + long life(); + + /** + * The number of flows pointing to this meter. + * + * @return a reference count + */ + long referenceCount(); + + /** + * Number of packets processed by this meter. + * + * @return a packet count + */ + long packetsSeen(); + + /** + * Number of bytes processed by this meter. + * + * @return a byte count + */ + long bytesSeen(); + + /** + * A meter builder. + */ + interface Builder { + + /** + * Assigns the target device for this meter. + * + * @param deviceId a device id + * @return this + */ + Builder forDevice(DeviceId deviceId); + + /** + * Assigns the id to this meter. + * + * @param id a e + * @return this + */ + Builder withId(MeterId id); + + /** + * Assigns the application that built this meter. + * + * @param appId an application id + * @return this + */ + Builder fromApp(ApplicationId appId); + + /** + * Assigns the @See Unit to use for this meter. + * Defaults to kb/s + * + * @param unit a unit + * @return this + */ + Builder withUnit(Unit unit); + + /** + * Sets this meter as applicable to burst traffic only. + * Defaults to false. + * + * @return this + */ + Builder burst(); + + /** + * Assigns bands to this meter. There must be at least one band. + * + * @param bands a collection of bands + * @return this + */ + Builder withBands(Collection bands); + + /** + * Builds the meter based on the specified parameters. + * + * @return a meter + */ + Meter build(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterContext.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterContext.java new file mode 100644 index 00000000..574bdca9 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterContext.java @@ -0,0 +1,38 @@ +/* + * 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; + +/** + * A context permitting the application to be notified when the + * meter installation has been successful. + */ +public interface MeterContext { + + /** + * Invoked on successful installation of the meter. + * + * @param op a meter + */ + default void onSuccess(MeterRequest op) {} + + /** + * Invoked when error is encountered while installing a meter. + * + * @param op a meter + * @param reason the reason why it failed + */ + default void onError(MeterRequest op, MeterFailReason reason) {} +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterEntry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterEntry.java new file mode 100644 index 00000000..178a564c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterEntry.java @@ -0,0 +1,57 @@ +/* + * 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; + +/** + * Represents a stored meter. + */ +public interface MeterEntry extends Meter { + + /** + * Updates the state of this meter. + * + * @param state a meter state + */ + void setState(MeterState state); + + /** + * Set the amount of time the meter has existed in seconds. + * + * @param life number of seconds + */ + void setLife(long life); + + /** + * Sets the number of flows which are using this meter. + * + * @param count a reference count. + */ + void setReferenceCount(long count); + + /** + * Updates the number of packets seen by this meter. + * + * @param packets a packet count. + */ + void setProcessedPackets(long packets); + + /** + * Updates the number of bytes seen by the meter. + * + * @param bytes a byte counter. + */ + void setProcessedBytes(long bytes); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterEvent.java new file mode 100644 index 00000000..72f0a53a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterEvent.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.meter; + +import org.onosproject.event.AbstractEvent; + +/** + * Entity that represents Meter events. + */ +public class MeterEvent extends AbstractEvent { + + + public enum Type { + /** + * A meter addition was requested. + */ + METER_ADD_REQ, + + /** + * A meter removal was requested. + */ + METER_REM_REQ + } + + + /** + * Creates an event of a given type and for the specified meter and the + * current time. + * + * @param type meter event type + * @param meter event subject + */ + public MeterEvent(Type type, Meter meter) { + super(type, meter); + } + + /** + * Creates an event of a given type and for the specified meter and time. + * + * @param type meter event type + * @param meter event subject + * @param time occurrence time + */ + public MeterEvent(Type type, Meter meter, long time) { + super(type, meter, time); + } + + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterFailReason.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterFailReason.java new file mode 100644 index 00000000..8683e2a2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterFailReason.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.meter; + +/** + * Enum used to represent a meter failure condition. + */ +public enum MeterFailReason { + /** + * A meter with the same identifier already exists. + * Essentially a duplicate meter exists. + */ + EXISTING_METER, + + /** + * The device does not support any more meters. + */ + OUT_OF_METERS, + + /** + * The device does not support any more bands for this meter. + */ + OUT_OF_BANDS, + + /** + * The meter that was attempted to be modified is unknown. + */ + UNKNOWN, + + /** + * The operation for this meter installation timed out. + */ + TIMEOUT, + + /** + * Invalid meter definition. + */ + INVALID_METER, + + /** + * The target device is unknown. + */ + UNKNOWN_DEVICE, + + /** + * Unknown command. + */ + UNKNOWN_COMMAND, + + /** + * Unknown flags. + */ + UNKNOWN_FLAGS, + + /** + * Bad rate value. + */ + BAD_RATE, + + /** + * Bad burst size value. + */ + BAD_BURST, + + /** + * Bad band. + */ + BAD_BAND, + + /** + * Bad value value. + */ + BAD_BAND_VALUE + + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterId.java new file mode 100644 index 00000000..872de2d8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterId.java @@ -0,0 +1,78 @@ +/* + * 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 static com.google.common.base.Preconditions.checkArgument; + +/** + * A representation of a meter id. + * Uniquely identifies a meter system wide. + */ +public final class MeterId { + + static final long MAX = 0xFFFF0000; + + private final long id; + + public static final MeterId SLOWPATH = new MeterId(0xFFFFFFFD); + public static final MeterId CONTROLLER = new MeterId(0xFFFFFFFE); + public static final MeterId ALL = new MeterId(0xFFFFFFFF); + + private MeterId(long id) { + checkArgument(id >= MAX, "id cannot be larger than 0xFFFF0000"); + this.id = id; + } + + /** + * The integer representation of the meter id. + * + * @return a long + */ + public long id() { + return id; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + MeterId meterId = (MeterId) o; + + return id == meterId.id; + + } + + @Override + public int hashCode() { + return Long.hashCode(id); + } + + @Override + public String toString() { + return Long.toHexString(this.id); + } + + public static MeterId meterId(long id) { + return new MeterId(id); + + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterListener.java new file mode 100644 index 00000000..0a5e203f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterListener.java @@ -0,0 +1,24 @@ +/* + * 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 org.onosproject.event.EventListener; + +/** + * Entity capable of receiving Meter related events. + */ +public interface MeterListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterOperation.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterOperation.java new file mode 100644 index 00000000..437dd269 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterOperation.java @@ -0,0 +1,88 @@ +/* + * 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.MoreObjects; +import com.google.common.base.Objects; + +/** + * Representation of an operation on the meter table. + */ +public class MeterOperation { + + + /** + * Tyoe of meter operation. + */ + public enum Type { + ADD, + REMOVE, + MODIFY + } + + private final Meter meter; + private final Type type; + + + public MeterOperation(Meter meter, Type type) { + this.meter = meter; + this.type = type; + } + + /** + * Returns the type of operation. + * + * @return type + */ + public Type type() { + return type; + } + + /** + * Returns the meter. + * + * @return a meter + */ + public Meter meter() { + return meter; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("meter", meter) + .add("type", type) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + MeterOperation that = (MeterOperation) o; + return Objects.equal(meter, that.meter) && + Objects.equal(type, that.type); + } + + @Override + public int hashCode() { + return Objects.hashCode(meter, type); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterOperations.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterOperations.java new file mode 100644 index 00000000..92b0c3aa --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterOperations.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.net.meter; + +import com.google.common.collect.ImmutableList; + +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Immutable collection of meter operation to be used between + * core and provider layers of group subsystem. + * + */ +public final class MeterOperations { + private final List operations; + + /** + * Creates a immutable list of meter operation. + * + * @param operations list of meter operation + */ + public MeterOperations(List operations) { + this.operations = ImmutableList.copyOf(checkNotNull(operations)); + } + + /** + * Returns immutable list of Meter operation. + * + * @return list of Meter operation + */ + public List operations() { + return operations; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterProvider.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterProvider.java new file mode 100644 index 00000000..4655e234 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterProvider.java @@ -0,0 +1,48 @@ +/* + * 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 org.onosproject.net.DeviceId; +import org.onosproject.net.provider.Provider; + +/** + * Abstraction of a Meter provider. + */ +public interface MeterProvider extends Provider { + + /** + * Performs a batch of meter operation on the specified device with the + * specified parameters. + * + * @param deviceId device identifier on which the batch of group + * operations to be executed + * @param meterOps immutable list of meter operation + */ + void performMeterOperation(DeviceId deviceId, + MeterOperations meterOps); + + + /** + * Performs a meter operation on the specified device with the + * specified parameters. + * + * @param deviceId device identifier on which the batch of group + * operations to be executed + * @param meterOp a meter operation + */ + void performMeterOperation(DeviceId deviceId, + MeterOperation meterOp); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterProviderRegistry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterProviderRegistry.java new file mode 100644 index 00000000..019ca19a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterProviderRegistry.java @@ -0,0 +1,27 @@ +/* + * 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 org.onosproject.net.provider.ProviderRegistry; + +/** + * Abstraction for a meter provider registry. + */ +public interface MeterProviderRegistry + extends ProviderRegistry { +} + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterProviderService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterProviderService.java new file mode 100644 index 00000000..85c0c43e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterProviderService.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.meter; + +import org.onosproject.net.DeviceId; +import org.onosproject.net.provider.ProviderService; + +import java.util.Collection; + +/** + * Service through which meter providers can inject information + * into the core. + */ +public interface MeterProviderService extends ProviderService { + + /** + * Notifies the core that a meter operaton failed for a + * specific reason. + * @param operation the failed operation + * @param reason the failure reason + */ + void meterOperationFailed(MeterOperation operation, + MeterFailReason reason); + + /** + * Pushes the collection of meters observed on the data plane as + * well as their associated statistics. + * + * @param deviceId a device id + * @param meterEntries a collection of meter entries + */ + void pushMeterMetrics(DeviceId deviceId, + Collection meterEntries); + + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterRequest.java new file mode 100644 index 00000000..fd11ca41 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterRequest.java @@ -0,0 +1,147 @@ +/* + * 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 org.onosproject.core.ApplicationId; +import org.onosproject.net.DeviceId; + +import java.util.Collection; +import java.util.Optional; + +/** + * Represents a generalized meter request to be deployed on a device. + */ +public interface MeterRequest { + + enum Type { + ADD, + MODIFY, + REMOVE + } + + /** + * The target device for this meter. + * + * @return a device id + */ + DeviceId deviceId(); + + /** + * The id of the application which created this meter. + * + * @return an application id + */ + ApplicationId appId(); + + /** + * The unit used within this meter. + * + * @return the unit + */ + Meter.Unit unit(); + + /** + * Signals whether this meter applies to bursts only. + * + * @return a boolean + */ + boolean isBurst(); + + /** + * The collection of bands to apply on the dataplane. + * + * @return a collection of bands. + */ + Collection bands(); + + /** + * Returns the callback context for this meter. + * + * @return an optional meter context + */ + Optional context(); + + /** + * A meter builder. + */ + interface Builder { + + /** + * Assigns the target device for this meter. + * + * @param deviceId a device id + * @return this + */ + Builder forDevice(DeviceId deviceId); + + /** + * Assigns the application that built this meter. + * + * @param appId an application id + * @return this + */ + Builder fromApp(ApplicationId appId); + + /** + * Assigns the @See Unit to use for this meter. + * Defaults to kb/s + * + * @param unit a unit + * @return this + */ + Builder withUnit(Meter.Unit unit); + + /** + * Sets this meter as applicable to burst traffic only. + * Defaults to false. + * + * @return this + */ + Builder burst(); + + /** + * Assigns bands to this meter. There must be at least one band. + * + * @param bands a collection of bands + * @return this + */ + Builder withBands(Collection bands); + + /** + * Assigns an execution context for this meter request. + * + * @param context a meter context + * @return this + */ + Builder withContext(MeterContext context); + + /** + * Requests the addition of a meter. + * + * @return a meter request + */ + MeterRequest add(); + + /** + * Requests the removal of a meter. + * + * @return a meter request + */ + MeterRequest remove(); + + } + +} 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 new file mode 100644 index 00000000..bdc90eb7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterService.java @@ -0,0 +1,61 @@ +/* + * 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 org.onosproject.event.ListenerService; + +import java.util.Collection; + +/** + * Service for add/updating and removing meters. Meters are + * are assigned to flow to rate limit them and provide a certain + * quality of service. + */ +public interface MeterService + extends ListenerService { + + /** + * Adds a meter to the system and performs it installation. + * + * @param meter a meter + * @return a meter (with a meter id) + */ + Meter submit(MeterRequest meter); + + /** + * Remove a meter from the system and the dataplane. + * + * @param meter a meter to remove + * @param meterId the meter id of the meter to remove. + */ + void withdraw(MeterRequest meter, MeterId meterId); + + /** + * Fetch the meter by the meter id. + * + * @param id a meter id + * @return a meter + */ + Meter getMeter(MeterId id); + + /** + * Fetches all the meters. + * + * @return a collection of meters + */ + Collection getAllMeters(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterState.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterState.java new file mode 100644 index 00000000..3b936099 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterState.java @@ -0,0 +1,43 @@ +/* + * 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; + +/** + * Represents the state of the meter as seen by the store. + */ +public enum MeterState { + + /** + * The meter is in the process of being added. + */ + PENDING_ADD, + + /** + * THe meter has been added. + */ + ADDED, + + /** + * The meter is in the process of being removed. + */ + PENDING_REMOVE, + + /** + * The meter has been removed. + */ + REMOVED, + +} 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 new file mode 100644 index 00000000..5112a4a3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStore.java @@ -0,0 +1,90 @@ +/* + * 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 org.onosproject.store.Store; + +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +/** + * Entity that stores and distributed meter objects. + */ +public interface MeterStore extends Store { + + /** + * Adds a meter to the store. + * + * @param meter a meter + * @return a future indicating the result of the store operation + */ + CompletableFuture storeMeter(Meter meter); + + /** + * Deletes a meter from the store. + * + * @param meter a meter + * @return a future indicating the result of the store operation + */ + CompletableFuture deleteMeter(Meter meter); + + /** + * Updates a meter whose meter id is the same as the passed meter. + * + * @param meter a new meter + * @return a future indicating the result of the store operation + */ + CompletableFuture updateMeter(Meter meter); + + /** + * Updates a given meter's state with the provided state. + * + * @param meter a meter + */ + void updateMeterState(Meter meter); + + /** + * Obtains a meter matching the given meter id. + * + * @param meterId a meter id + * @return a meter + */ + Meter getMeter(MeterId meterId); + + /** + * Returns all meters stored in the store. + * + * @return a collection of meters + */ + Collection getAllMeters(); + + /** + * Update the store by deleting the failed meter. + * Notifies the delegate that the meter failed to allow it + * to nofity the app. + * + * @param op a failed meter operation + * @param reason a failure reason + */ + void failedMeter(MeterOperation op, MeterFailReason reason); + + /** + * Delete this meter immediately. + * @param m a meter + */ + void deleteMeterNow(Meter m); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStoreDelegate.java new file mode 100644 index 00000000..9bfeb42f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStoreDelegate.java @@ -0,0 +1,24 @@ +/* + * 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 org.onosproject.store.StoreDelegate; + +/** + * Meter store delegate abstraction. + */ +public interface MeterStoreDelegate extends StoreDelegate { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStoreResult.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStoreResult.java new file mode 100644 index 00000000..7a26746f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/MeterStoreResult.java @@ -0,0 +1,66 @@ +/* + * 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 java.util.Optional; + +/** + * An entity used to indicate whether the store operation passed. + */ +public final class MeterStoreResult { + + + private final Type type; + private final Optional reason; + + public enum Type { + SUCCESS, + FAIL + } + + private MeterStoreResult(Type type, MeterFailReason reason) { + this.type = type; + this.reason = Optional.ofNullable(reason); + } + + public Type type() { + return type; + } + + public Optional reason() { + return reason; + } + + /** + * A successful store opertion. + * + * @return a meter store result + */ + public static MeterStoreResult success() { + return new MeterStoreResult(Type.SUCCESS, null); + } + + /** + * A failed store operation. + * + * @param reason a failure reason + * @return a meter store result + */ + public static MeterStoreResult fail(MeterFailReason reason) { + return new MeterStoreResult(Type.FAIL, reason); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/package-info.java new file mode 100644 index 00000000..258634da --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/meter/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. + */ + +/** + * Flow meter model and related services. + */ +package org.onosproject.net.meter; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceAdminService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceAdminService.java new file mode 100644 index 00000000..e94ee452 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceAdminService.java @@ -0,0 +1,75 @@ +/* + * 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.newresource; + +import com.google.common.annotations.Beta; + +import java.util.Arrays; +import java.util.List; + +/** + * Service for administering resource service behavior. + */ +@Beta +public interface ResourceAdminService { + /** + * Register resources as the children of the parent resource path. + * + * @param parent parent resource path under which the resource are registered + * @param children resources to be registered as the children of the parent + * @param type of resources + * @return true if registration is successfully done, false otherwise. Registration + * succeeds when each resource is not registered or unallocated. + */ + default boolean registerResources(ResourcePath parent, T... children) { + return registerResources(parent, Arrays.asList(children)); + } + + /** + * Register resources as the children of the parent resource path. + * + * @param parent parent resource path under which the resource are registered + * @param children resources to be registered as the children of the parent + * @param type of resources + * @return true if registration is successfully done, false otherwise. Registration + * succeeds when each resource is not registered or unallocated. + */ + boolean registerResources(ResourcePath parent, List children); + + /** + * Unregister resources as the children of the parent resource path. + * + * @param parent parent resource path under which the resource are unregistered + * @param children resources to be unregistered as the children of the parent + * @param type of resources + * @return true if unregistration is successfully done, false otherwise. Unregistration + * succeeds when each resource is not registered or unallocated. + */ + default boolean unregisterResources(ResourcePath parent, T... children) { + return unregisterResources(parent, Arrays.asList(children)); + } + + /** + * Unregister resources as the children of the parent resource path. + * + * @param parent parent resource path under which the resource are unregistered + * @param children resources to be unregistered as the children of the parent + * @param type of resources + * @return true if unregistration is successfully done, false otherwise. Unregistration + * succeeds when each resource is not registered or unallocated. + */ + boolean unregisterResources(ResourcePath parent, List children); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceAllocation.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceAllocation.java new file mode 100644 index 00000000..e6980267 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceAllocation.java @@ -0,0 +1,94 @@ +/* + * 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.newresource; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents allocation of resource which is identified by the specifier. + */ +@Beta +public class ResourceAllocation { + + private final ResourcePath resource; + private final ResourceConsumer consumer; + + /** + * Creates an instance with the specified subject, resource and consumer. + * + * @param resource resource of the subject + * @param consumer consumer ot this resource + */ + public ResourceAllocation(ResourcePath resource, ResourceConsumer consumer) { + this.resource = checkNotNull(resource); + this.consumer = consumer; + } + + // for serialization + private ResourceAllocation() { + this.resource = null; + this.consumer = null; + } + + /** + * Returns the specifier of the resource this allocation uses. + * + * @return the specifier of the resource this allocation uses + */ + public ResourcePath resource() { + return resource; + } + + /** + * Returns the consumer of this resource. + * + * @return the consumer of this resource + */ + public ResourceConsumer consumer() { + return consumer; + } + + @Override + public int hashCode() { + return Objects.hash(resource, consumer); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ResourceAllocation)) { + return false; + } + final ResourceAllocation that = (ResourceAllocation) obj; + return Objects.equals(this.resource, that.resource) + && Objects.equals(this.consumer, that.consumer); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("resource", resource) + .add("consumer", consumer) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceConsumer.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceConsumer.java new file mode 100644 index 00000000..1f67e204 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceConsumer.java @@ -0,0 +1,25 @@ +/* + * 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.newresource; + +import com.google.common.annotations.Beta; + +/** + * Marker interface representing an entity using resource. + */ +@Beta +public interface ResourceConsumer { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourcePath.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourcePath.java new file mode 100644 index 00000000..3aa29f6b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourcePath.java @@ -0,0 +1,146 @@ +/* + * 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.newresource; + +import com.google.common.annotations.Beta; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An object that is used to locate a resource in a network. + * A ResourcePath represents a path that is hierarchical and composed of a sequence + * of elementary resources that are not globally identifiable. A ResourcePath can be a globally + * unique resource identifier. + * + * Users of this class must keep the semantics of resources regarding the hierarchical structure. + * For example, resource path, Link:1/VLAN ID:100, is valid, but resource path, VLAN ID:100/Link:1 + * is not valid because a link is not a sub-component of a VLAN ID. + */ +@Beta +public final class ResourcePath { + + private final List resources; + + public static final ResourcePath ROOT = new ResourcePath(ImmutableList.of()); + + public static ResourcePath child(ResourcePath parent, Object child) { + ImmutableList components = ImmutableList.builder() + .addAll(parent.components()) + .add(child) + .build(); + return new ResourcePath(components); + } + + /** + * Creates an resource path from the specified components. + * + * @param components components of the path. The order represents hierarchical structure of the resource. + */ + public ResourcePath(Object... components) { + this(Arrays.asList(components)); + } + + /** + * Creates an resource path from the specified components. + * + * @param components components of the path. The order represents hierarchical structure of the resource. + */ + public ResourcePath(List components) { + checkNotNull(components); + + this.resources = ImmutableList.copyOf(components); + } + + // for serialization + private ResourcePath() { + this.resources = null; + } + + /** + * Returns the components of this resource path. + * + * @return the components of this resource path + */ + public List components() { + return resources; + } + + /** + * Returns the parent resource path of this instance. + * E.g. if this path is Link:1/VLAN ID:100, the return value is the resource path for Link:1. + * + * @return the parent resource path of this instance. + * If there is no parent, empty instance will be returned. + */ + public Optional parent() { + if (!isRoot()) { + return Optional.of(new ResourcePath(resources.subList(0, resources.size() - 1))); + } + + return Optional.empty(); + } + + /** + * Returns true if the path represents root. + * + * @return true if the path represents root, false otherwise. + */ + public boolean isRoot() { + return resources.size() == 0; + } + + /** + * Returns the last component of this instance. + * + * @return the last component of this instance. + * The return value is equal to the last object of {@code components()}. + */ + public Object lastComponent() { + int last = resources.size() - 1; + return resources.get(last); + } + + @Override + public int hashCode() { + return resources.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ResourcePath)) { + return false; + } + final ResourcePath that = (ResourcePath) obj; + return Objects.equals(this.resources, that.resources); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("resources", resources) + .toString(); + } +} 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 new file mode 100644 index 00000000..618042a3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java @@ -0,0 +1,155 @@ +/* + * 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.newresource; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableList; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Service for allocating/releasing resource(s) and retrieving allocation(s) and availability. + */ +@Beta +public interface ResourceService { + /** + * Allocates the specified resource to the specified user. + * + * @param consumer resource user which the resource is allocated to + * @param resource resource to be allocated + * @return allocation information enclosed by Optional. If the allocation fails, the return value is empty + */ + default Optional allocate(ResourceConsumer consumer, ResourcePath resource) { + checkNotNull(consumer); + checkNotNull(resource); + + List allocations = allocate(consumer, ImmutableList.of(resource)); + if (allocations.isEmpty()) { + return Optional.empty(); + } + + assert allocations.size() == 1; + + ResourceAllocation allocation = allocations.get(0); + + assert allocation.resource().equals(resource); + + // cast is ensured by the assertions above + return Optional.of(allocation); + } + + /** + * Transactionally allocates the specified resources to the specified user. + * All allocations are made when this method succeeds, or no allocation is made when this method fails. + * + * @param consumer resource user which the resources are allocated to + * @param resources resources to be allocated + * @return non-empty list of allocation information if succeeded, otherwise empty list + */ + List allocate(ResourceConsumer consumer, List resources); + + /** + * Transactionally allocates the specified resources to the specified user. + * All allocations are made when this method succeeds, or no allocation is made when this method fails. + * + * @param consumer resource user which the resources are allocated to + * @param resources resources to be allocated + * @return non-empty list of allocation information if succeeded, otherwise empty list + */ + default List allocate(ResourceConsumer consumer, ResourcePath... resources) { + checkNotNull(consumer); + checkNotNull(resources); + + return allocate(consumer, Arrays.asList(resources)); + } + + /** + * Releases the specified resource allocation. + * + * @param allocation resource allocation to be released + * @return true if succeeded, otherwise false + */ + default boolean release(ResourceAllocation allocation) { + checkNotNull(allocation); + + return release(ImmutableList.of(allocation)); + } + + /** + * Transactionally releases the specified resource allocations. + * All allocations are released when this method succeeded, or no allocation is released when this method fails. + * + * @param allocations resource allocations to be released + * @return true if succeeded, otherwise false + */ + boolean release(List allocations); + + /** + * Transactionally releases the specified resource allocations. + * All allocations are released when this method succeeded, or no allocation is released when this method fails. + * + * @param allocations resource allocations to be released + * @return true if succeeded, otherwise false + */ + default boolean release(ResourceAllocation... allocations) { + checkNotNull(allocations); + + return release(ImmutableList.copyOf(allocations)); + } + + /** + * Transactionally releases the resources allocated to the specified consumer. + * All allocations are released when this method succeeded, or no allocation is released when this method fails. + * + * @param consumer consumer whose allocated resources are to be released + * @return true if succeeded, otherwise false + */ + boolean release(ResourceConsumer consumer); + + /** + * Returns allocated resources being as children of the specified parent and being the specified resource type. + * + * @param parent parent resource path + * @param cls class to specify a type of resource + * @param type of the resource + * @return non-empty collection of resource allocations if resources are allocated with the subject and type, + * empty collection if no resource is allocated with the subject and type + */ + Collection getResourceAllocations(ResourcePath parent, Class cls); + + /** + * Returns resources allocated to the specified consumer. + * + * @param consumer consumer whose allocated resources are to be returned + * @return resources allocated to the consumer + */ + Collection getResourceAllocations(ResourceConsumer consumer); + + /** + * Returns the availability of the specified resource. + * + * @param resource resource to check the availability + * @return true if available, otherwise false + */ + boolean isAvailable(ResourcePath resource); + + // TODO: listener and event mechanism need to be considered +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java new file mode 100644 index 00000000..fc2eba70 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java @@ -0,0 +1,90 @@ +package org.onosproject.net.newresource; + +import com.google.common.annotations.Beta; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +/** + * Service for storing resource and consumer information. + */ +@Beta +public interface ResourceStore { + + /** + * Registers the resources in transactional way. + * Resource registration must be done before resource allocation. The state after completion + * of this method is all the resources are registered, or none of the given resources is registered. + * The whole registration fails when any one of the resource can't be registered. + * + * @param resources resources to be registered + * @return true if the registration succeeds, false otherwise + */ + boolean register(List resources); + + /** + * Unregisters the resources in transactional way. + * The state after completion of this method is all the resources are unregistered, + * or none of the given resources is unregistered. The whole unregistration fails when any one of the + * resource can't be unregistered. + * + * @param resources resources to be unregistered + * @return true if the registration succeeds, false otherwise + */ + boolean unregister(List resources); + + /** + * Allocates the specified resources to the specified consumer in transactional way. + * The state after completion of this method is all the resources are allocated to the consumer, + * or no resource is allocated to the consumer. The whole allocation fails when any one of + * the resource can't be allocated. + * + * @param resources resources to be allocated + * @param consumer resource consumer which the resources are allocated to + * @return true if the allocation succeeds, false otherwise. + */ + boolean allocate(List resources, ResourceConsumer consumer); + + /** + * Releases the specified resources allocated to the specified corresponding consumers + * in transactional way. The state after completion of this method is all the resources + * are released from the consumer, or no resource is released. The whole release fails + * when any one of the resource can't be released. The size of the list of resources and + * that of consumers must be equal. The resource and consumer with the same position from + * the head of each list correspond to each other. + * + * @param resources resources to be released + * @param consumers resource consumers to whom the resource allocated to + * @return true if succeeds, otherwise false + */ + boolean release(List resources, List consumers); + + /** + * Returns the resource consumer to whom the specified resource is allocated. + * + * @param resource resource whose allocated consumer to be returned + * @return resource consumer who are allocated the resource + */ + Optional getConsumer(ResourcePath resource); + + /** + * Returns a collection of the resources allocated to the specified consumer. + * + * @param consumer resource consumer whose allocated resource are searched for + * @return a collection of the resources allocated to the specified consumer + */ + Collection getResources(ResourceConsumer consumer); + + /** + * Returns a collection of the resources which are children of the specified parent and + * whose type is the specified class. + * + * @param parent parent of the resources to be returned + * @param cls class instance of the children + * @param type of the resource + * @return a collection of the resources which belongs to the specified subject and + * whose type is the specified class. + */ + Collection getAllocatedResources(ResourcePath parent, Class cls); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/package-info.java new file mode 100644 index 00000000..52bb8588 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/newresource/package-info.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +/** + * Generic network resource model and services for resource allocation and + * resource tracking. + */ +package org.onosproject.net.newresource; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/package-info.java new file mode 100644 index 00000000..34b4de21 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Network model entities & service API definitions. + */ +package org.onosproject.net; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultInboundPacket.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultInboundPacket.java new file mode 100644 index 00000000..96f872f5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultInboundPacket.java @@ -0,0 +1,91 @@ +/* + * Copyright 2014 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; + +import org.onosproject.net.ConnectPoint; +import org.onlab.packet.Ethernet; + +import java.nio.ByteBuffer; +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Default implementation of an immutable inbound packet. + */ +public final class DefaultInboundPacket implements InboundPacket { + + private final ConnectPoint receivedFrom; + private final Ethernet parsed; + private final ByteBuffer unparsed; + + /** + * Creates an immutable inbound packet. + * + * @param receivedFrom connection point where received + * @param parsed parsed ethernet frame + * @param unparsed unparsed raw bytes + */ + public DefaultInboundPacket(ConnectPoint receivedFrom, Ethernet parsed, + ByteBuffer unparsed) { + this.receivedFrom = receivedFrom; + this.parsed = parsed; + this.unparsed = unparsed; + } + + @Override + public ConnectPoint receivedFrom() { + return receivedFrom; + } + + @Override + public Ethernet parsed() { + return parsed; + } + + @Override + public ByteBuffer unparsed() { + // FIXME: figure out immutability here + return unparsed; + } + + @Override + public int hashCode() { + return Objects.hash(receivedFrom, parsed, unparsed); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof InboundPacket) { + final DefaultInboundPacket other = (DefaultInboundPacket) obj; + return Objects.equals(this.receivedFrom, other.receivedFrom) && + Objects.equals(this.parsed, other.parsed) && + Objects.equals(this.unparsed, other.unparsed); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("receivedFrom", receivedFrom) + .add("parsed", parsed) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultOutboundPacket.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultOutboundPacket.java new file mode 100644 index 00000000..5bd4c986 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultOutboundPacket.java @@ -0,0 +1,89 @@ +/* + * Copyright 2014 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; + +import java.nio.ByteBuffer; +import java.util.Objects; + +import org.onosproject.net.DeviceId; +import org.onosproject.net.flow.TrafficTreatment; + +import com.google.common.base.MoreObjects; + +/** + * Default implementation of an immutable outbound packet. + */ +public final class DefaultOutboundPacket implements OutboundPacket { + private final DeviceId sendThrough; + private final TrafficTreatment treatment; + private final ByteBuffer data; + + /** + * Creates an immutable outbound packet. + * + * @param sendThrough identifier through which to send the packet + * @param treatment list of packet treatments + * @param data raw packet data + */ + public DefaultOutboundPacket(DeviceId sendThrough, + TrafficTreatment treatment, ByteBuffer data) { + this.sendThrough = sendThrough; + this.treatment = treatment; + this.data = data; + } + + @Override + public DeviceId sendThrough() { + return sendThrough; + } + + @Override + public TrafficTreatment treatment() { + return treatment; + } + + @Override + public ByteBuffer data() { + // FIXME: figure out immutability here + return data; + } + + @Override + public int hashCode() { + return Objects.hash(sendThrough, treatment, data); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof OutboundPacket) { + final DefaultOutboundPacket other = (DefaultOutboundPacket) obj; + return Objects.equals(this.sendThrough, other.sendThrough) && + Objects.equals(this.treatment, other.treatment) && + Objects.equals(this.data, other.data); + } + return false; + } + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("sendThrough", sendThrough) + .add("treatment", treatment) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultPacketContext.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultPacketContext.java new file mode 100644 index 00000000..166269f9 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultPacketContext.java @@ -0,0 +1,95 @@ +/* + * Copyright 2014-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; + +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.TrafficTreatment.Builder; + +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.onosproject.security.AppGuard.checkPermission; +import static org.onosproject.security.AppPermission.Type.*; + +/** + * Default implementation of a packet context. + */ +public abstract class DefaultPacketContext implements PacketContext { + + private final long time; + private final InboundPacket inPkt; + private final OutboundPacket outPkt; + private final TrafficTreatment.Builder builder; + + private final AtomicBoolean block; + + /** + * Creates a new packet context. + * + * @param time creation time + * @param inPkt inbound packet + * @param outPkt outbound packet + * @param block whether the context is blocked or not + */ + protected DefaultPacketContext(long time, InboundPacket inPkt, + OutboundPacket outPkt, boolean block) { + super(); + this.time = time; + this.inPkt = inPkt; + this.outPkt = outPkt; + this.block = new AtomicBoolean(block); + this.builder = DefaultTrafficTreatment.builder(); + } + + @Override + public long time() { + checkPermission(PACKET_READ); + return time; + } + + @Override + public InboundPacket inPacket() { + checkPermission(PACKET_READ); + return inPkt; + } + + @Override + public OutboundPacket outPacket() { + checkPermission(PACKET_READ); + return outPkt; + } + + @Override + public Builder treatmentBuilder() { + checkPermission(PACKET_READ); + return builder; + } + + @Override + public abstract void send(); + + @Override + public boolean block() { + checkPermission(PACKET_WRITE); + return this.block.getAndSet(true); + } + + @Override + public boolean isHandled() { + checkPermission(PACKET_READ); + return this.block.get(); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultPacketRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultPacketRequest.java new file mode 100644 index 00000000..ce2eb118 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/DefaultPacketRequest.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.packet; + +import com.google.common.base.MoreObjects; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.flow.TrafficSelector; + +import java.util.Objects; + +/** + * Default implementation of a packet request. + */ +public final class DefaultPacketRequest implements PacketRequest { + private final TrafficSelector selector; + private final PacketPriority priority; + private final ApplicationId appId; + + /** + * Creates a new packet request. + * + * @param selector traffic selector + * @param priority intercept priority + * @param appId application id + */ + public DefaultPacketRequest(TrafficSelector selector, PacketPriority priority, + ApplicationId appId) { + this.selector = selector; + this.priority = priority; + this.appId = appId; + } + + public TrafficSelector selector() { + return selector; + } + + public PacketPriority priority() { + return priority; + } + + public ApplicationId appId() { + return appId; + } + + @Override + public int hashCode() { + return Objects.hash(selector, priority, appId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final DefaultPacketRequest other = (DefaultPacketRequest) obj; + return Objects.equals(this.selector, other.selector) + && Objects.equals(this.priority, other.priority) + && Objects.equals(this.appId, other.appId); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this.getClass()) + .add("selector", selector) + .add("priority", priority) + .add("appId", appId).toString(); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/InboundPacket.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/InboundPacket.java new file mode 100644 index 00000000..3fd58149 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/InboundPacket.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014 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; + +import org.onosproject.net.ConnectPoint; +import org.onlab.packet.Ethernet; + +import java.nio.ByteBuffer; + +/** + * Represents a data packet intercepted from an infrastructure device. + */ +public interface InboundPacket { + + /** + * Returns the device and port from where the packet was received. + * + * @return connection point where received + */ + ConnectPoint receivedFrom(); + + /** + * Returns the parsed form of the packet. + * + * @return parsed Ethernet frame; null if the packet is not an Ethernet + * frame or one for which there is no parser + */ + Ethernet parsed(); + + /** + * Unparsed packet data. + * + * @return raw packet bytes + */ + ByteBuffer unparsed(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/OutboundPacket.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/OutboundPacket.java new file mode 100644 index 00000000..9e9329fa --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/OutboundPacket.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014 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; + +import org.onosproject.net.DeviceId; +import org.onosproject.net.flow.TrafficTreatment; + +import java.nio.ByteBuffer; + +/** + * Represents an outbound data packet that is to be emitted to network via + * an infrastructure device. + */ +public interface OutboundPacket { + + /** + * Returns the identity of a device through which this packet should be + * sent. + * + * @return device identity + */ + DeviceId sendThrough(); + + /** + * Returns how the outbound packet should be treated. + * + * @return output treatment + */ + TrafficTreatment treatment(); + + /** + * Returns immutable view of the raw data to be sent. + * + * @return data to emit + */ + ByteBuffer data(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketContext.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketContext.java new file mode 100644 index 00000000..004adc87 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketContext.java @@ -0,0 +1,73 @@ +/* + * Copyright 2014 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; + +import org.onosproject.net.flow.TrafficTreatment; + +/** + * Represents context for processing an inbound packet, and (optionally) + * emitting a corresponding outbound packet. + */ +public interface PacketContext { + + /** + * Returns the time when the packet was received. + * + * @return the time in millis since start of epoch + */ + long time(); + + /** + * Returns the inbound packet being processed. + * + * @return inbound packet + */ + InboundPacket inPacket(); + + /** + * Returns the view of the outbound packet. + * + * @return outbound packet + */ + OutboundPacket outPacket(); + + /** + * Returns a builder for constructing traffic treatment. + * + * @return traffic treatment builder + */ + TrafficTreatment.Builder treatmentBuilder(); + + /** + * Triggers the outbound packet to be sent. + */ + void send(); + + /** + * Blocks the outbound packet from being sent from this point onward. + * + * @return whether the outbound packet is blocked. + */ + boolean block(); + + /** + * Indicates whether the outbound packet is handled, i.e. sent or blocked. + * + * @return true uf the packed is handled + */ + boolean isHandled(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketEvent.java new file mode 100644 index 00000000..7b0a5ed7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketEvent.java @@ -0,0 +1,56 @@ +/* + * Copyright 2014 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; + +import org.onosproject.event.AbstractEvent; + +/** + * Describes a packet event. + */ +public class PacketEvent extends AbstractEvent { + + /** + * Type of packet events. + */ + public enum Type { + /** + * Signifies that the packet should be emitted out a local port. + */ + EMIT + } + + /** + * Creates an event of the given type for the specified packet. + * + * @param type the type of the event + * @param packet the packet the event is about + */ + public PacketEvent(Type type, OutboundPacket packet) { + super(type, packet); + } + + /** + * Creates an event of the given type for the specified packet at the given + * time. + * + * @param type the type of the event + * @param packet the packet the event is about + * @param time the time of the event + */ + public PacketEvent(Type type, OutboundPacket packet, long time) { + super(type, packet, time); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketPriority.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketPriority.java new file mode 100644 index 00000000..68c0a838 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketPriority.java @@ -0,0 +1,53 @@ +/* + * 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; + +/** + * Priorities available to applications for requests for packets from the data + * plane. + */ +public enum PacketPriority { + /** + * High priority for control traffic. This will result in all traffic + * matching the selector being sent to the controller. + */ + CONTROL(40000), + + /** + * Low priority for reactive applications. Packets are only sent to the + * controller if they fail to match any of the rules installed in the switch. + */ + REACTIVE(5); + + private final int priorityValue; + + private PacketPriority(int priorityValue) { + this.priorityValue = priorityValue; + } + + /** + * Returns the integer value of the priority level. + * + * @return priority value + */ + public int priorityValue() { + return priorityValue; + } + + public String toString() { + return String.valueOf(priorityValue); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProcessor.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProcessor.java new file mode 100644 index 00000000..98886775 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProcessor.java @@ -0,0 +1,83 @@ +/* + * Copyright 2014 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; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Abstraction of an inbound packet processor. + */ +public interface PacketProcessor { + + static final int ADVISOR_MAX = Integer.MAX_VALUE / 3; + static final int DIRECTOR_MAX = (Integer.MAX_VALUE / 3) * 2; + static final int OBSERVER_MAX = Integer.MAX_VALUE; + + /** + * Returns a priority in the ADVISOR range, where processors can take early action and + * influence the packet context. However, they cannot handle the packet (i.e. call send() or block()). + * The valid range is from 1 to ADVISOR_MAX. + * Processors in this range get to see the packet first. + * + * @param priority priority within ADVISOR range + * @return overall priority + */ + static int advisor(int priority) { + int overallPriority = priority + 1; + checkArgument(overallPriority > 0 && overallPriority <= ADVISOR_MAX, + "Priority not within ADVISOR range"); + return overallPriority; + } + + /** + * Returns a priority in the DIRECTOR range, where processors can handle the packet. + * The valid range is from ADVISOR_MAX+1 to DIRECTOR_MAX. + * Processors in this range get to see the packet second, after ADVISORS. + * + * @param priority priority within the DIRECTOR range + * @return overall priority + */ + static int director(int priority) { + int overallPriority = ADVISOR_MAX + priority + 1; + checkArgument(overallPriority > ADVISOR_MAX && overallPriority <= DIRECTOR_MAX, + "Priority not within DIRECTOR range"); + return overallPriority; + } + + /** + * Returns a priority in the OBSERVER range, where processors cannot take any action, + * but can observe what action has been taken until then. + * The valid range is from DIRECTOR_MAX+1 to OBSERVER_MAX. + * Processors in this range get to see the packet last, after ADVISORS and DIRECTORS. + * + * @param priority priority within the OBSERVER range + * @return overall priority + */ + static int observer(int priority) { + int overallPriority = DIRECTOR_MAX + priority + 1; + checkArgument(overallPriority > DIRECTOR_MAX && overallPriority <= OBSERVER_MAX, + "Priority not within OBSERVER range"); + return overallPriority; + } + + /** + * Processes the inbound packet as specified in the given context. + * + * @param context packet processing context + */ + void process(PacketContext context); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProvider.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProvider.java new file mode 100644 index 00000000..8d55f0d1 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProvider.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014 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; + +import org.onosproject.net.provider.Provider; + +/** + * Abstraction of a packet provider capable of emitting packets. + */ +public interface PacketProvider extends Provider { + + /** + * Emits the specified outbound packet onto the network. + * + * @param packet outbound packet + */ + void emit(OutboundPacket packet); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProviderRegistry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProviderRegistry.java new file mode 100644 index 00000000..6e73253e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProviderRegistry.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 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; + +import org.onosproject.net.provider.ProviderRegistry; + +/** + * Abstraction of an infrastructure packet provider registry. + */ +public interface PacketProviderRegistry +extends ProviderRegistry { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProviderService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProviderService.java new file mode 100644 index 00000000..1aaee65f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketProviderService.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 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; + +import org.onosproject.net.provider.ProviderService; + +/** + * Entity capable of processing inbound packets. + */ +public interface PacketProviderService extends ProviderService { + + /** + * Submits inbound packet context for processing. This processing will be + * done synchronously, i.e. run-to-completion. + * + * @param context inbound packet context + */ + void processPacket(PacketContext context); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketRequest.java new file mode 100644 index 00000000..dc09219a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketRequest.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.packet; + +import org.onosproject.core.ApplicationId; +import org.onosproject.net.flow.TrafficSelector; + +/** + * Represents a packet request made to devices. + */ +public interface PacketRequest { + + /** + * Obtain the traffic selector. + * + * @return a traffic selector + */ + TrafficSelector selector(); + + /** + * Obtain the priority. + * + * @return a PacketPriority + */ + PacketPriority priority(); + + /** + * Obtain the application id. + * + * @return an application id + */ + ApplicationId appId(); + +} 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 new file mode 100644 index 00000000..06c416ec --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketService.java @@ -0,0 +1,79 @@ +/* + * Copyright 2014-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; + +import org.onosproject.core.ApplicationId; +import org.onosproject.net.flow.TrafficSelector; + +/** + * Service for intercepting data plane packets and for emitting synthetic + * outbound packets. + */ +public interface PacketService { + + // TODO: ponder better ordering scheme that does not require absolute numbers + + /** + * Adds the specified processor to the list of packet processors. + * It will be added into the list in the order of priority. The higher + * numbers will be processing the packets after the lower numbers. + * + * @param processor processor to be added + * @param priority priority in the reverse natural order + * @throws java.lang.IllegalArgumentException if a processor with the + * given priority already exists + */ + void addProcessor(PacketProcessor processor, int priority); + + // TODO allow processors to register for particular types of packets + + /** + * Removes the specified processor from the processing pipeline. + * + * @param processor packet processor + */ + void removeProcessor(PacketProcessor processor); + + /** + * Requests that packets matching the given selector are punted from the + * dataplane to the controller. + * + * @param selector the traffic selector used to match packets + * @param priority the priority of the rule + * @param appId the application ID of the requester + */ + void requestPackets(TrafficSelector selector, PacketPriority priority, + ApplicationId appId); + + /** + * Cancels previous packet requests for packets matching the given + * selector to be punted from the dataplane to the controller. + * + * @param selector the traffic selector used to match packets + * @param priority the priority of the rule + * @param appId the application ID of the requester + */ + void cancelPackets(TrafficSelector selector, PacketPriority priority, + ApplicationId appId); + + /** + * Emits the specified outbound packet onto the network. + * + * @param packet outbound packet + */ + void emit(OutboundPacket packet); + +} 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 new file mode 100644 index 00000000..ff45cc0c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStore.java @@ -0,0 +1,59 @@ +/* + * Copyright 2014-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; + +import org.onosproject.store.Store; + +import java.util.Set; + +/** + * Manages routing of outbound packets. + */ +public interface PacketStore extends Store { + + /** + * Decides which instance should emit the packet and forwards the packet to + * that instance. The relevant PacketManager is notified via the + * PacketStoreDelegate that it should emit the packet. + * + * @param packet the packet to emit + */ + void emit(OutboundPacket packet); + + /** + * 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); + + /** + * 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); + + /** + * Obtains all existing requests in the system. + * + * @return a set of packet requests + */ + Set existingRequests(); + +} 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 new file mode 100644 index 00000000..bf5c3cc0 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/PacketStoreDelegate.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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; + +import org.onosproject.store.StoreDelegate; + +/** + * Packet store delegate abstraction. + */ +public interface PacketStoreDelegate extends StoreDelegate { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/package-info.java new file mode 100644 index 00000000..0b9ea377 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/packet/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2014 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. + */ + +/** + * Mechanism for processing inbound packets intercepted from the data plane and + * for emitting outbound packets onto the data plane. + */ +package org.onosproject.net.packet; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractListenerProviderRegistry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractListenerProviderRegistry.java new file mode 100644 index 00000000..ff67c6da --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractListenerProviderRegistry.java @@ -0,0 +1,66 @@ +/* + * 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.provider; + +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onosproject.event.Event; +import org.onosproject.event.EventDeliveryService; +import org.onosproject.event.EventListener; +import org.onosproject.event.ListenerRegistry; +import org.onosproject.event.ListenerService; + +/** + * Basis for components which need to export listener mechanism. + */ +@Component(componentAbstract = true) +public abstract class AbstractListenerProviderRegistry, + P extends Provider, S extends ProviderService

> + extends AbstractProviderRegistry implements ListenerService { + + // If only Java supported mixins... + + protected final ListenerRegistry listenerRegistry = new ListenerRegistry<>(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected EventDeliveryService eventDispatcher; + + @Override + public void addListener(L listener) { + listenerRegistry.addListener(listener); + } + + @Override + public void removeListener(L listener) { + listenerRegistry.removeListener(listener); + } + + + /** + * Safely posts the specified event to the local event dispatcher. + * If there is no event dispatcher or if the event is null, this method + * is a noop. + * + * @param event event to be posted; may be null + */ + protected void post(E event) { + if (event != null && eventDispatcher != null) { + eventDispatcher.post(event); + } + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractProvider.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractProvider.java new file mode 100644 index 00000000..a4926dd3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractProvider.java @@ -0,0 +1,39 @@ +/* + * Copyright 2014 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.provider; + +/** + * Base provider implementation. + */ +public abstract class AbstractProvider implements Provider { + + private final ProviderId providerId; + + /** + * Creates a provider with the supplier identifier. + * + * @param id provider id + */ + protected AbstractProvider(ProviderId id) { + this.providerId = id; + } + + @Override + public ProviderId id() { + return providerId; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractProviderRegistry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractProviderRegistry.java new file mode 100644 index 00000000..bcf5fae0 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractProviderRegistry.java @@ -0,0 +1,111 @@ +/* + * Copyright 2014 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.provider; + +import com.google.common.collect.ImmutableSet; +import org.onosproject.net.DeviceId; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +/** + * Base implementation of provider registry. + * + * @param

type of the information provider + * @param type of the provider service + */ +public abstract class AbstractProviderRegistry

> + implements ProviderRegistry { + + private final Map providers = new HashMap<>(); + private final Map services = new HashMap<>(); + private final Map providersByScheme = new HashMap<>(); + + /** + * Creates a new provider service bound to the specified provider. + * + * @param provider provider + * @return provider service + */ + protected abstract S createProviderService(P provider); + + @Override + public synchronized S register(P provider) { + checkNotNull(provider, "Provider cannot be null"); + checkState(!services.containsKey(provider.id()), "Provider %s already registered", provider.id()); + + // If the provider is a primary one, check for a conflict. + ProviderId pid = provider.id(); + checkState(pid.isAncillary() || !providersByScheme.containsKey(pid.scheme()), + "A primary provider with id %s is already registered", + providersByScheme.get(pid.scheme())); + + S service = createProviderService(provider); + services.put(provider.id(), service); + providers.put(provider.id(), provider); + + // Register the provider by URI scheme only if it is not ancillary. + if (!pid.isAncillary()) { + providersByScheme.put(pid.scheme(), provider); + } + + return service; + } + + @Override + public synchronized void unregister(P provider) { + checkNotNull(provider, "Provider cannot be null"); + S service = services.get(provider.id()); + if (service != null && service instanceof AbstractProviderService) { + ((AbstractProviderService) service).invalidate(); + services.remove(provider.id()); + providers.remove(provider.id()); + if (!provider.id().isAncillary()) { + providersByScheme.remove(provider.id().scheme()); + } + } + } + + @Override + public synchronized Set getProviders() { + return ImmutableSet.copyOf(services.keySet()); + } + + /** + * Returns the provider registered with the specified provider ID. + * + * @param providerId provider identifier + * @return provider + */ + protected synchronized P getProvider(ProviderId providerId) { + return providers.get(providerId); + } + + /** + * Returns the provider for the specified device ID based on URI scheme. + * + * @param deviceId device identifier + * @return provider bound to the URI scheme + */ + protected synchronized P getProvider(DeviceId deviceId) { + return providersByScheme.get(deviceId.uri().getScheme()); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractProviderService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractProviderService.java new file mode 100644 index 00000000..6c926d88 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/AbstractProviderService.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014 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.provider; + +import static com.google.common.base.Preconditions.checkState; + +/** + * Base implementation of a provider service, which tracks the provider to + * which it is issued and can be invalidated. + * + * @param

type of the information provider + */ +public abstract class AbstractProviderService

implements ProviderService

{ + + private boolean isValid = true; + private final P provider; + + /** + * Creates a provider service on behalf of the specified provider. + * + * @param provider provider to which this service is being issued + */ + protected AbstractProviderService(P provider) { + this.provider = provider; + } + + /** + * Invalidates this provider service. + */ + public void invalidate() { + isValid = false; + } + + /** + * Checks the validity of this provider service. + * + * @throws java.lang.IllegalStateException if the service is no longer valid + */ + public void checkValidity() { + checkState(isValid, "Provider service is no longer valid"); + } + + @Override + public P provider() { + return provider; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/Provider.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/Provider.java new file mode 100644 index 00000000..84465ab7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/Provider.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014 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.provider; + +/** + * Abstraction of a provider of information about network environment. + */ +public interface Provider { + + /** + * Returns the provider identifier. + * + * @return provider identification + */ + ProviderId id(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/ProviderId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/ProviderId.java new file mode 100644 index 00000000..2c959afd --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/ProviderId.java @@ -0,0 +1,135 @@ +/* + * Copyright 2014 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.provider; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * External identity of a {@link org.onosproject.net.provider.Provider} family. + * It also carriers two designations of external characteristics, the URI + * scheme and primary/ancillary indicator. + *

+ * The device URI scheme is used to determine applicability of a provider to + * operations on a specific device. The ancillary indicator serves to designate + * a provider as a primary or ancillary. + *

+ *

+ * A {@link org.onosproject.net.provider.ProviderRegistry} uses this designation + * to permit only one primary provider per device URI scheme. Multiple + * ancillary providers can register with the same device URI scheme however. + *

+ */ +public class ProviderId { + + /** + * Represents no provider ID. + */ + public static final ProviderId NONE = new ProviderId("none", "none"); + + private final String scheme; + private final String id; + private final boolean ancillary; + + // For serialization + private ProviderId() { + scheme = null; + id = null; + ancillary = false; + } + + /** + * Creates a new primary provider identifier from the specified string. + * The providers are expected to follow the reverse DNS convention, e.g. + * {@code org.onosproject.provider.of.device} + * + * @param scheme device URI scheme to which this provider is bound, e.g. "of", "snmp" + * @param id string identifier + */ + public ProviderId(String scheme, String id) { + this(scheme, id, false); + } + + /** + * Creates a new provider identifier from the specified string. + * The providers are expected to follow the reverse DNS convention, e.g. + * {@code org.onosproject.provider.of.device} + * + * @param scheme device URI scheme to which this provider is bound, e.g. "of", "snmp" + * @param id string identifier + * @param ancillary ancillary provider indicator + */ + public ProviderId(String scheme, String id, boolean ancillary) { + this.scheme = checkNotNull(scheme, "Scheme cannot be null"); + this.id = checkNotNull(id, "ID cannot be null"); + this.ancillary = ancillary; + } + + /** + * Returns the device URI scheme to which this provider is bound. + * + * @return device URI scheme + */ + public String scheme() { + return scheme; + } + + /** + * Returns the device URI scheme specific id portion. + * + * @return id + */ + public String id() { + return id; + } + + /** + * Indicates whether this identifier designates an ancillary providers. + * + * @return true if the provider is ancillary; false if primary + */ + public boolean isAncillary() { + return ancillary; + } + + @Override + public int hashCode() { + return Objects.hash(scheme, id); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ProviderId) { + final ProviderId other = (ProviderId) obj; + return Objects.equals(this.scheme, other.scheme) && + Objects.equals(this.id, other.id) && + this.ancillary == other.ancillary; + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this).add("scheme", scheme).add("id", id) + .add("ancillary", ancillary).toString(); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/ProviderRegistry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/ProviderRegistry.java new file mode 100644 index 00000000..3c2009ad --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/ProviderRegistry.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014 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.provider; + +import java.util.Set; + +/** + * Registry for tracking information providers with the core. + * + * @param

type of the information provider + * @param type of the provider service + */ +public interface ProviderRegistry

> { + + /** + * Registers the supplied provider with the core. + * + * @param provider provider to be registered + * @return provider service for injecting information into core + * @throws java.lang.IllegalArgumentException if the provider is registered already + */ + S register(P provider); + + /** + * Unregisters the supplied provider. As a result the previously issued + * provider service will be invalidated and any subsequent invocations + * of its methods may throw {@link java.lang.IllegalStateException}. + *

+ * Unregistering a provider that has not been previously registered results + * in a no-op. + *

+ * + * @param provider provider to be unregistered + */ + void unregister(P provider); + + /** + * Returns a set of currently registered provider identities. + * + * @return set of provider identifiers + */ + Set getProviders(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/ProviderService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/ProviderService.java new file mode 100644 index 00000000..5c469276 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/ProviderService.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 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.provider; + +/** + * Abstraction of a service through which providers can inject information + * about the network environment into the core. + * + * @param

type of the information provider + */ +public interface ProviderService

{ + + /** + * Returns the provider to which this service has been issued. + * + * @return provider to which this service has been assigned + */ + P provider(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/package-info.java new file mode 100644 index 00000000..d279f56a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/provider/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Base abstractions related to network entity providers and their brokers. + */ +package org.onosproject.net.provider; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpService.java new file mode 100644 index 00000000..8ffe17a4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpService.java @@ -0,0 +1,64 @@ +/* + * Copyright 2014-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.proxyarp; + +import org.onlab.packet.Ethernet; +import org.onlab.packet.IpAddress; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.packet.PacketContext; + +/** + * Service for processing arp requests on behalf of applications. + */ +// TODO: move to the peer host package +public interface ProxyArpService { + + /** + * Returns whether this particular IP address is known to the system. + * + * @param addr an IP address + * @return true if know, false otherwise + */ + boolean isKnown(IpAddress addr); + + /** + * Sends a reply for a given request. If the host is not known then the + * arp or neighbor solicitation will be flooded at all edge ports. + * + * @param eth an arp or neighbor solicitation request + * @param inPort the port the request was received on + */ + void reply(Ethernet eth, ConnectPoint inPort); + + /** + * Forwards an ARP or neighbor solicitation request to its destination. + * Floods at the edg the request if the destination is not known. + * + * @param eth an ethernet frame containing an ARP or neighbor solicitation + * request. + * @param inPort the port the request was received on + */ + void forward(Ethernet eth, ConnectPoint inPort); + + /** + * Handles a arp or neighbor solicitation packet. + * Replies to arp or neighbor solicitation requests and forwards request + * to the right place. + * @param context the packet context to handle + * @return true if handled, false otherwise. + */ + boolean handlePacket(PacketContext context); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpStore.java new file mode 100644 index 00000000..b6564212 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpStore.java @@ -0,0 +1,45 @@ +/* + * 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.proxyarp; + +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Host; + +import java.nio.ByteBuffer; + +/** + * State distribution mechanism for the proxy ARP service. + */ +public interface ProxyArpStore { + + /** + * Forwards an ARP or neighbor solicitation request to its destination. + * Floods at the edg the request if the destination is not known. + * + * @param outPort the port the request was received on + * @param subject subject host + * @param packet an ethernet frame containing an ARP or neighbor + * solicitation request + */ + void forward(ConnectPoint outPort, Host subject, ByteBuffer packet); + + /** + * Associates the specified delegate with the store. + * + * @param delegate store delegate + */ + void setDelegate(ProxyArpStoreDelegate delegate); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpStoreDelegate.java new file mode 100644 index 00000000..d0e273c8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/ProxyArpStoreDelegate.java @@ -0,0 +1,35 @@ +/* + * 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.proxyarp; + +import org.onosproject.net.ConnectPoint; + +import java.nio.ByteBuffer; + +/** + * Proxy ARP store delegate. + */ +public interface ProxyArpStoreDelegate { + + /** + * Emits ARP or neighbour discovery response packet. + * + * @param outPort output connection point + * @param packet packet to emit + */ + void emitResponse(ConnectPoint outPort, ByteBuffer packet); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/package-info.java new file mode 100644 index 00000000..6ddd4926 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/proxyarp/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Base abstractions related to the proxy arp service. + */ +package org.onosproject.net.proxyarp; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceAllocation.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceAllocation.java new file mode 100644 index 00000000..01b69b2a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceAllocation.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014 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; + +import com.google.common.annotations.Beta; + +/** + * Abstraction of allocated resource. + */ +@Beta +public interface ResourceAllocation { + /** + * Returns the resource type. + * + * @return the resource type + */ + ResourceType type(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceAllocationException.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceAllocationException.java new file mode 100644 index 00000000..c3d1fcc7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceAllocationException.java @@ -0,0 +1,36 @@ +/* + * 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; + +import com.google.common.annotations.Beta; + +/** + * Exception thrown for resource allocation errors. + */ +@Beta +public class ResourceAllocationException extends ResourceException { + public ResourceAllocationException() { + super(); + } + + public ResourceAllocationException(String message) { + super(message); + } + + public ResourceAllocationException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceException.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceException.java new file mode 100644 index 00000000..31e82d5d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceException.java @@ -0,0 +1,51 @@ +/* + * 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; + +import com.google.common.annotations.Beta; + +/** + * Represents a resource related error. + */ +@Beta +public class ResourceException extends RuntimeException { + + /** + * Constructs an exception with no message and no underlying cause. + */ + public ResourceException() { + } + + /** + * Constructs an exception with the specified message. + * + * @param message the message describing the specific nature of the error + */ + public ResourceException(String message) { + super(message); + } + + /** + * Constructs an exception with the specified message and the underlying cause. + * + * @param message the message describing the specific nature of the error + * @param cause the underlying cause of this error + */ + public ResourceException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceId.java new file mode 100644 index 00000000..722ec4d7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceId.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 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; + +import com.google.common.annotations.Beta; + +/** + * Resource identifier. + */ +@Beta +public interface ResourceId { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceRequest.java new file mode 100644 index 00000000..fb53f120 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceRequest.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014 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; + +import com.google.common.annotations.Beta; + +/** + * Abstraction of resource request. + */ +@Beta +public interface ResourceRequest { + /** + * Returns the resource type. + * + * @return the resource type + */ + ResourceType type(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceType.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceType.java new file mode 100644 index 00000000..75832134 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/ResourceType.java @@ -0,0 +1,39 @@ +/* + * Copyright 2014-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; + +import com.google.common.annotations.Beta; + +/** + * Represents types for link resources. + */ +@Beta +public enum ResourceType { + /** + * Lambda resource type. + */ + LAMBDA, + + /** + * Bandwidth resource type. + */ + BANDWIDTH, + + /** + * MPLS label resource type. + */ + MPLS_LABEL, +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceService.java new file mode 100644 index 00000000..5468dfb7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceService.java @@ -0,0 +1,85 @@ +/* + * 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 com.google.common.annotations.Beta; +import org.onosproject.net.Port; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentId; + +import java.util.Set; + +/** + * Service for providing device resources. + */ +@Beta +public interface DeviceResourceService { + /** + * Request a set of ports needed to satisfy the intent. + * + * @param ports set of ports to allocate + * @param intent the intent + * @return true if ports were successfully allocated, false otherwise + */ + boolean requestPorts(Set ports, Intent intent); + + /** + * Returns the set of ports allocated for an intent. + * + * @param intentId the intent ID + * @return set of allocated ports + */ + Set getAllocations(IntentId intentId); + + /** + * Returns the intent allocated to a port. + * + * @param port the port + * @return intent ID allocated to the port + */ + IntentId getAllocations(Port port); + + /** + * Request a mapping between the given intents. + * + * @param keyIntentId the key intent ID + * @param valIntentId the value intent ID + * @return true if mapping was successful, false otherwise + */ + boolean requestMapping(IntentId keyIntentId, IntentId valIntentId); + + /** + * Returns the intents mapped to a lower intent. + * + * @param intentId the intent ID + * @return the set of intent IDs + */ + Set getMapping(IntentId intentId); + + /** + * Release mapping of given intent. + * + * @param intentId intent ID + */ + void releaseMapping(IntentId intentId); + + /** + * Release ports associated with given intent ID. + * + * @param intentId intent ID + */ + void releasePorts(IntentId intentId); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceStore.java new file mode 100644 index 00000000..a52a843f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/DeviceResourceStore.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.resource.device; + +import org.onosproject.net.DeviceId; +import org.onosproject.net.Port; +import org.onosproject.net.intent.IntentId; + +import java.util.Set; + +public interface DeviceResourceStore { + /** + * Returns unallocated ports on the given device. + * + * @param deviceId device ID + * @return set of unallocated ports + */ + Set getFreePorts(DeviceId deviceId); + + /** + * Allocates the given ports to the given intent. + * + * @param ports set of ports to allocate + * @param intentId intent ID + * @return true if allocation was successful, false otherwise + */ + boolean allocatePorts(Set ports, IntentId intentId); + + /** + * Returns set of ports allocated for an intent. + * + * @param intentId the intent ID + * @return set of allocated ports + */ + Set getAllocations(IntentId intentId); + + /** + * Returns intent allocated to a port. + * + * @param port the port + * @return intent ID allocated to the port + */ + IntentId getAllocations(Port port); + + /** + * 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); + + /** + * Releases the ports allocated to the given intent. + * + * @param intentId intent ID + * @return true if release was successful, false otherwise + */ + boolean releasePorts(IntentId intentId); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/package-info.java new file mode 100644 index 00000000..3ced37dc --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/device/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. + */ + +/** + * Services for reserving devices as network resources. + */ +package org.onosproject.net.resource.device; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResource.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResource.java new file mode 100644 index 00000000..fe21e042 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResource.java @@ -0,0 +1,72 @@ +/* + * Copyright 2014-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.link; + +import org.onlab.util.Bandwidth; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Representation of bandwidth resource in bps. + */ +public final class BandwidthResource implements LinkResource { + + private final Bandwidth bandwidth; + + /** + * Creates a new instance with given bandwidth. + * + * @param bandwidth bandwidth value to be assigned + */ + public BandwidthResource(Bandwidth bandwidth) { + this.bandwidth = checkNotNull(bandwidth); + } + + // Constructor for serialization + private BandwidthResource() { + this.bandwidth = null; + } + + /** + * Returns bandwidth as a double value. + * + * @return bandwidth as a double value + */ + public double toDouble() { + return bandwidth.bps(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof BandwidthResource) { + BandwidthResource that = (BandwidthResource) obj; + return Objects.equals(this.bandwidth, that.bandwidth); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(this.bandwidth); + } + + @Override + public String toString() { + return String.valueOf(this.bandwidth); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceAllocation.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceAllocation.java new file mode 100644 index 00000000..74f6e102 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceAllocation.java @@ -0,0 +1,77 @@ +/* + * Copyright 2014 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.link; + +import com.google.common.base.MoreObjects; +import org.onosproject.net.resource.ResourceAllocation; +import org.onosproject.net.resource.ResourceType; + +import java.util.Objects; + +/** + * Representation of allocated bandwidth resource. + */ +public class BandwidthResourceAllocation implements ResourceAllocation { + private final BandwidthResource bandwidth; + + /** + * Creates a new {@link BandwidthResourceRequest} with {@link BandwidthResource} + * object. + * + * @param bandwidth {@link BandwidthResource} object to be requested + */ + public BandwidthResourceAllocation(BandwidthResource bandwidth) { + this.bandwidth = bandwidth; + } + + /** + * Returns the bandwidth resource. + * + * @return the bandwidth resource + */ + public BandwidthResource bandwidth() { + return bandwidth; + } + + @Override + public ResourceType type() { + return ResourceType.BANDWIDTH; + } + + @Override + public int hashCode() { + return Objects.hash(bandwidth); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final BandwidthResourceAllocation other = (BandwidthResourceAllocation) obj; + return Objects.equals(this.bandwidth, other.bandwidth()); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("bandwidth", bandwidth) + .toString(); + } +} 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 new file mode 100644 index 00000000..91cc3d19 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/BandwidthResourceRequest.java @@ -0,0 +1,77 @@ +/* + * Copyright 2014-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.link; + +import java.util.Objects; + +import com.google.common.base.MoreObjects; +import org.onosproject.net.resource.ResourceRequest; +import org.onosproject.net.resource.ResourceType; + +/** + * Representation of a request for bandwidth resource. + */ +public class BandwidthResourceRequest implements ResourceRequest { + private final BandwidthResource bandwidth; + + /** + * Creates a new {@link BandwidthResourceRequest} with {@link BandwidthResource} + * object. + * + * @param bandwidth {@link BandwidthResource} object to be requested + */ + public BandwidthResourceRequest(BandwidthResource bandwidth) { + this.bandwidth = bandwidth; + } + + /** + * Returns the bandwidth resource. + * + * @return the bandwidth resource + */ + public BandwidthResource bandwidth() { + return bandwidth; + } + + @Override + public ResourceType type() { + return ResourceType.BANDWIDTH; + } + + @Override + public int hashCode() { + return Objects.hash(bandwidth); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final BandwidthResourceAllocation other = (BandwidthResourceAllocation) obj; + return Objects.equals(this.bandwidth, other.bandwidth()); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("bandwidth", bandwidth) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceAllocations.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceAllocations.java new file mode 100644 index 00000000..379bf71e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceAllocations.java @@ -0,0 +1,112 @@ +/* + * Copyright 2014 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.link; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +import org.onosproject.net.Link; +import org.onosproject.net.intent.IntentId; +import org.onosproject.net.resource.ResourceAllocation; +import org.onosproject.net.resource.ResourceRequest; +import org.onosproject.net.resource.ResourceType; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.Map.Entry; +import java.util.Set; + +/** + * Implementation of {@link LinkResourceAllocations}. + */ +public class DefaultLinkResourceAllocations implements LinkResourceAllocations { + private final LinkResourceRequest request; + // TODO: probably should be using LinkKey instead + private final Map> allocations; + + /** + * Creates a new link resource allocations. + * + * @param request requested resources + * @param allocations allocated resources + */ + public DefaultLinkResourceAllocations(LinkResourceRequest request, + Map> allocations) { + this.request = checkNotNull(request); + ImmutableMap.Builder> builder + = ImmutableMap.builder(); + for (Entry> e : allocations.entrySet()) { + builder.put(e.getKey(), ImmutableSet.copyOf(e.getValue())); + } + this.allocations = builder.build(); + } + + public IntentId intentId() { + return request.intentId(); + } + + public Collection links() { + return request.links(); + } + + public Set resources() { + return request.resources(); + } + + @Override + public ResourceType type() { + return null; + } + + @Override + public Set getResourceAllocation(Link link) { + Set result = allocations.get(link); + if (result == null) { + result = Collections.emptySet(); + } + return result; + } + + @Override + public int hashCode() { + return Objects.hash(request, allocations); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final DefaultLinkResourceAllocations other = (DefaultLinkResourceAllocations) obj; + return Objects.equals(this.request, other.request) + && Objects.equals(this.allocations, other.allocations); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("allocations", allocations) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java new file mode 100644 index 00000000..5153aebf --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/DefaultLinkResourceRequest.java @@ -0,0 +1,186 @@ +/* + * Copyright 2014-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.link; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.Objects; + +import org.onlab.util.Bandwidth; +import org.onosproject.net.Link; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.IntentId; + +import com.google.common.collect.ImmutableSet; + +import org.onosproject.net.intent.constraint.BandwidthConstraint; +import org.onosproject.net.intent.constraint.LambdaConstraint; +import org.onosproject.net.resource.ResourceRequest; +import org.onosproject.net.resource.ResourceType; + +/** + * Implementation of {@link LinkResourceRequest}. + */ +public final class DefaultLinkResourceRequest implements LinkResourceRequest { + + private final IntentId intentId; + private final Collection links; + private final Set resources; + + /** + * Creates a new link resource request with the given ID, links, and + * resource requests. + * + * @param intentId intent ID related to this request + * @param links a set of links for the request + * @param resources a set of resources to be requested + */ + private DefaultLinkResourceRequest(IntentId intentId, + Collection links, + Set resources) { + this.intentId = intentId; + this.links = ImmutableSet.copyOf(links); + this.resources = ImmutableSet.copyOf(resources); + } + + + @Override + public ResourceType type() { + return null; + } + + @Override + public IntentId intentId() { + return intentId; + } + + @Override + public Collection links() { + return links; + } + + @Override + public Set resources() { + return resources; + } + + /** + * Returns builder of link resource request. + * + * @param intentId intent ID related to this request + * @param links a set of links for the request + * @return builder of link resource request + */ + public static LinkResourceRequest.Builder builder( + IntentId intentId, Collection links) { + return new Builder(intentId, links); + } + + /** + * Builder of link resource request. + */ + public static final class Builder implements LinkResourceRequest.Builder { + private IntentId intentId; + private Collection links; + private Set resources; + + /** + * Creates a new link resource request. + * + * @param intentId intent ID related to this request + * @param links a set of links for the request + */ + private Builder(IntentId intentId, Collection links) { + this.intentId = intentId; + this.links = links; + this.resources = new HashSet<>(); + } + + /** + * Adds lambda request. + * + * @return self + */ + @Override + public Builder addLambdaRequest() { + resources.add(new LambdaResourceRequest()); + return this; + } + + /** + * Adds Mpls request. + * + * @return self + */ + @Override + public Builder addMplsRequest() { + resources.add(new MplsLabelResourceRequest()); + return this; + } + + /** + * Adds bandwidth request with bandwidth value. + * + * @param bandwidth bandwidth value in bits per second to be requested + * @return self + */ + @Override + public Builder addBandwidthRequest(double bandwidth) { + resources.add(new BandwidthResourceRequest(new BandwidthResource(Bandwidth.bps(bandwidth)))); + return this; + } + + @Override + public LinkResourceRequest.Builder addConstraint(Constraint constraint) { + if (constraint instanceof LambdaConstraint) { + return addLambdaRequest(); + } else if (constraint instanceof BandwidthConstraint) { + BandwidthConstraint bw = (BandwidthConstraint) constraint; + return addBandwidthRequest(bw.bandwidth().toDouble()); + } + return this; + } + + /** + * Returns link resource request. + * + * @return link resource request + */ + @Override + public LinkResourceRequest build() { + return new DefaultLinkResourceRequest(intentId, links, resources); + } + } + + @Override + public int hashCode() { + return Objects.hash(intentId, links); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final DefaultLinkResourceRequest other = (DefaultLinkResourceRequest) obj; + return Objects.equals(this.intentId, other.intentId) + && Objects.equals(this.links, other.links); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResource.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResource.java new file mode 100644 index 00000000..3733e467 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResource.java @@ -0,0 +1,93 @@ +/* + * Copyright 2014 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.link; + +import org.onosproject.net.IndexedLambda; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Representation of lambda resource. + */ +public final class LambdaResource implements LinkResource { + + private final IndexedLambda lambda; + + /** + * Creates a new instance with given lambda. + * + * @param lambda lambda to be assigned + */ + private LambdaResource(IndexedLambda lambda) { + this.lambda = checkNotNull(lambda); + } + + // Constructor for serialization + private LambdaResource() { + this.lambda = null; + } + + /** + * Creates a new instance with the given index of lambda. + * + * @param lambda index value of lambda to be assigned + * @return {@link LambdaResource} instance with the given lambda + */ + public static LambdaResource valueOf(int lambda) { + return valueOf(new IndexedLambda(lambda)); + } + + /** + * Creates a new instance with the given lambda. + * + * @param lambda lambda to be assigned + * @return {@link LambdaResource} instance with the given lambda + */ + public static LambdaResource valueOf(IndexedLambda lambda) { + return new LambdaResource(lambda); + } + + /** + * Returns lambda as an int value. + * + * @return lambda as an int value + */ + public int toInt() { + return (int) lambda.index(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof LambdaResource) { + LambdaResource that = (LambdaResource) obj; + return Objects.equals(this.lambda, that.lambda); + } + return false; + } + + @Override + public int hashCode() { + return lambda.hashCode(); + } + + @Override + public String toString() { + return String.valueOf(this.lambda); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceAllocation.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceAllocation.java new file mode 100644 index 00000000..545f025f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceAllocation.java @@ -0,0 +1,77 @@ +/* + * Copyright 2014 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.link; + +import com.google.common.base.MoreObjects; +import org.onosproject.net.resource.ResourceAllocation; +import org.onosproject.net.resource.ResourceType; + +import java.util.Objects; + +/** + * Representation of allocated lambda resource. + */ +public class LambdaResourceAllocation implements ResourceAllocation { + private final LambdaResource lambda; + + @Override + public ResourceType type() { + return ResourceType.LAMBDA; + } + + /** + * Creates a new {@link LambdaResourceAllocation} with {@link LambdaResource} + * object. + * + * @param lambda allocated lambda + */ + public LambdaResourceAllocation(LambdaResource lambda) { + this.lambda = lambda; + } + + /** + * Returns the lambda resource. + * + * @return the lambda resource + */ + public LambdaResource lambda() { + return lambda; + } + + @Override + public int hashCode() { + return Objects.hash(lambda); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final LambdaResourceAllocation other = (LambdaResourceAllocation) obj; + return Objects.equals(this.lambda, other.lambda); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("lambda", lambda) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceRequest.java new file mode 100644 index 00000000..b0391f5a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LambdaResourceRequest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 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.link; + +import com.google.common.base.MoreObjects; +import org.onosproject.net.resource.ResourceRequest; +import org.onosproject.net.resource.ResourceType; + +/** + * Representation of a request for lambda resource. + */ +public class LambdaResourceRequest implements ResourceRequest { + + @Override + public ResourceType type() { + return ResourceType.LAMBDA; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResource.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResource.java new file mode 100644 index 00000000..ec06611e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResource.java @@ -0,0 +1,22 @@ +/* + * Copyright 2014 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.link; + +/** + * Abstraction of link resource. + */ +public interface LinkResource { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceAllocations.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceAllocations.java new file mode 100644 index 00000000..7828867c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceAllocations.java @@ -0,0 +1,59 @@ +/* + * Copyright 2014 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.link; + +import java.util.Collection; +import java.util.Set; + +import org.onosproject.net.Link; +import org.onosproject.net.intent.IntentId; +import org.onosproject.net.resource.ResourceAllocation; +import org.onosproject.net.resource.ResourceRequest; + +/** + * Representation of allocated link resources. + */ +public interface LinkResourceAllocations extends ResourceAllocation { + + /** + * Returns the {@link IntentId} associated with the request. + * + * @return the {@link IntentId} associated with the request + */ + IntentId intentId(); + + /** + * Returns the set of target links. + * + * @return the set of target links + */ + Collection links(); + + /** + * Returns the set of resource requests. + * + * @return the set of resource requests + */ + Set resources(); + + /** + * Returns allocated resource for the given link. + * + * @param link the target link + * @return allocated resource for the link + */ + Set getResourceAllocation(Link link); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceEvent.java new file mode 100644 index 00000000..3edb386a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceEvent.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014 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.link; + +import java.util.Collection; + +import org.onosproject.event.AbstractEvent; + +import com.google.common.collect.ImmutableList; + +/** + * Describes an event related to a Link Resource. + */ +public final class LinkResourceEvent + extends AbstractEvent> { + + /** + * Type of resource this event is for. + */ + public enum Type { + /** Additional resources are now available. */ + ADDITIONAL_RESOURCES_AVAILABLE + } + + /** + * Constructs a link resource event. + * + * @param type type of resource event to create + * @param linkResourceAllocations allocations that are now available + */ + public LinkResourceEvent(Type type, + Collection linkResourceAllocations) { + super(type, ImmutableList.copyOf(linkResourceAllocations)); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceListener.java new file mode 100644 index 00000000..599dd4fb --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceListener.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.link; + +import org.onosproject.event.EventListener; + +/** + * Entity for receiving link resource events. + */ +public interface LinkResourceListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java new file mode 100644 index 00000000..8023a92e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceRequest.java @@ -0,0 +1,93 @@ +/* + * Copyright 2014-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.link; + +import java.util.Collection; +import java.util.Set; + +import org.onosproject.net.Link; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.IntentId; +import org.onosproject.net.resource.ResourceRequest; + +/** + * Representation of a request for link resource. + */ +public interface LinkResourceRequest extends ResourceRequest { + + /** + * Returns the {@link IntentId} associated with the request. + * + * @return the {@link IntentId} associated with the request + */ + IntentId intentId(); + + /** + * Returns the set of target links. + * + * @return the set of target links + */ + Collection links(); + + /** + * Returns the set of resource requests. + * + * @return the set of resource requests + */ + Set resources(); + + /** + * Builder of link resource request. + */ + interface Builder { + /** + * Adds lambda request. + * + * @return self + */ + Builder addLambdaRequest(); + + /** + * Adds MPLS request. + * + * @return self + */ + Builder addMplsRequest(); + + /** + * Adds bandwidth request with bandwidth value. + * + * @param bandwidth bandwidth value to be requested + * @return self + */ + Builder addBandwidthRequest(double bandwidth); + + /** + * Adds the resources required for a constraint. + * + * @param constraint the constraint + * @return self + */ + Builder addConstraint(Constraint constraint); + + /** + * Returns link resource request. + * + * @return link resource request + */ + LinkResourceRequest build(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java new file mode 100644 index 00000000..6dc04dfc --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceService.java @@ -0,0 +1,95 @@ +/* + * Copyright 2014 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.link; + +import org.onosproject.event.ListenerService; +import org.onosproject.net.Link; +import org.onosproject.net.intent.IntentId; +import org.onosproject.net.resource.ResourceRequest; + +/** + * Service for providing link resource allocation. + */ +public interface LinkResourceService + extends ListenerService { + + /** + * Requests resources. + * + * @param req resources to be allocated + * @return allocated resources + */ + LinkResourceAllocations requestResources(LinkResourceRequest req); + + /** + * Releases resources. + * + * @param allocations resources to be released + */ + void releaseResources(LinkResourceAllocations allocations); + + /** + * Updates previously made allocations with a new resource request. + * + * @param req updated resource request + * @param oldAllocations old resource allocations + * @return new resource allocations + */ + LinkResourceAllocations updateResources(LinkResourceRequest req, + LinkResourceAllocations oldAllocations); + + /** + * Returns all allocated resources. + * + * @return allocated resources + */ + Iterable getAllocations(); + + /** + * Returns all allocated resources to given link. + * + * @param link a target link + * @return allocated resources + */ + Iterable getAllocations(Link link); + + /** + * Returns the resources allocated for an Intent. + * + * @param intentId the target Intent's id + * @return allocated resources for Intent + */ + LinkResourceAllocations getAllocations(IntentId intentId); + + /** + * Returns available resources for given link. + * + * @param link a target link + * @return available resources for the target link + */ + Iterable getAvailableResources(Link link); + + /** + * Returns available resources for given link. + * + * @param link a target link + * @param allocations allocations to be included as available + * @return available resources for the target link + */ + Iterable getAvailableResources(Link link, + LinkResourceAllocations allocations); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceStore.java new file mode 100644 index 00000000..e6674dbd --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceStore.java @@ -0,0 +1,73 @@ +/* + * Copyright 2014 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.link; + +import java.util.Set; + +import org.onosproject.net.Link; +import org.onosproject.net.intent.IntentId; +import org.onosproject.net.resource.ResourceAllocation; + +/** + * Manages link resources. + */ +public interface LinkResourceStore { + /** + * Returns free resources for given link. + * + * @param link a target link + * @return free resources for given link + */ + Set getFreeResources(Link link); + + /** + * Allocates resources. + * + * @param allocations resources to be allocated + */ + void allocateResources(LinkResourceAllocations allocations); + + /** + * Releases resources. + * + * @param allocations resources to be released + * @return the link resource event + */ + LinkResourceEvent releaseResources(LinkResourceAllocations allocations); + + /** + * Returns resources allocated for an Intent. + * + * @param intentId the target Intent's ID + * @return allocated resources or null if no resource is allocated + */ + LinkResourceAllocations getAllocations(IntentId intentId); + + /** + * Returns resources allocated for a link. + * + * @param link the target link + * @return allocated resources + */ + Iterable getAllocations(Link link); + + /** + * Returns all allocated resources. + * + * @return allocated resources + */ + Iterable getAllocations(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceStoreDelegate.java new file mode 100644 index 00000000..6c051d6a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResourceStoreDelegate.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.link; + +import org.onosproject.store.StoreDelegate; + +/** + * Link resource store delegate abstraction. + */ +public interface LinkResourceStoreDelegate extends StoreDelegate { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResources.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResources.java new file mode 100644 index 00000000..dc005227 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/LinkResources.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014 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.link; + +import java.util.Set; + +/** + * Abstraction of a resources of a link. + */ +public interface LinkResources { + + /** + * Returns resources as a set of {@link LinkResource}s. + * + * @return a set of {@link LinkResource}s + */ + Set resources(); + + /** + * Builder of {@link LinkResources}. + */ + interface Builder { + + /** + * Adds bandwidth resource. + *

+ * This operation adds given bandwidth to previous bandwidth and + * generates single bandwidth resource. + * + * @param bandwidth bandwidth value to be added + * @return self + */ + Builder addBandwidth(double bandwidth); + + /** + * Adds lambda resource. + * + * @param lambda lambda value to be added + * @return self + */ + Builder addLambda(int lambda); + + /** + * Builds an immutable link resources. + * + * @return link resources + */ + LinkResources build(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabel.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabel.java new file mode 100644 index 00000000..89c87760 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabel.java @@ -0,0 +1,75 @@ +/* + * Copyright 2014-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.link; + +import java.util.Objects; + +/** + * Representation of MPLS label resource. + */ +public final class MplsLabel implements LinkResource { + + private final org.onlab.packet.MplsLabel mplsLabel; + + + /** + * Creates a new instance with given MPLS label. + * + * @param mplsLabel MPLS Label value to be assigned + */ + public MplsLabel(int mplsLabel) { + this.mplsLabel = org.onlab.packet.MplsLabel.mplsLabel(mplsLabel); + } + + /** + * Creates a new instance with given MPLS label. + * + * @param mplsLabel mplsLabel value to be assigned + * @return {@link MplsLabel} instance with given bandwidth + */ + public static MplsLabel valueOf(int mplsLabel) { + return new MplsLabel(mplsLabel); + } + + /** + * Returns MPLS Label as an MPLS Label Object. + * + * @return MPLS label as an MPLS Label Object. + */ + public org.onlab.packet.MplsLabel label() { + return mplsLabel; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof MplsLabel) { + MplsLabel that = (MplsLabel) obj; + return Objects.equals(this.mplsLabel, that.mplsLabel); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(this.mplsLabel); + } + + @Override + public String toString() { + return String.valueOf(this.mplsLabel); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceAllocation.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceAllocation.java new file mode 100644 index 00000000..10911539 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceAllocation.java @@ -0,0 +1,78 @@ + /* + * Copyright 2014-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.link; + +import com.google.common.base.MoreObjects; +import org.onosproject.net.resource.ResourceAllocation; +import org.onosproject.net.resource.ResourceType; + +import java.util.Objects; + +/** + * Representation of allocated MPLS label resource. + */ +public class MplsLabelResourceAllocation implements ResourceAllocation { + private final MplsLabel mplsLabel; + + @Override + public ResourceType type() { + return ResourceType.MPLS_LABEL; + } + + /** + * Creates a new {@link MplsLabelResourceAllocation} with {@link MplsLabel} + * object. + * + * @param mplsLabel allocated MPLS Label + */ + public MplsLabelResourceAllocation(MplsLabel mplsLabel) { + this.mplsLabel = mplsLabel; + } + + /** + * Returns the MPLS label resource. + * + * @return the MPLS label resource + */ + public MplsLabel mplsLabel() { + return mplsLabel; + } + + @Override + public int hashCode() { + return Objects.hash(mplsLabel); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final MplsLabelResourceAllocation other = (MplsLabelResourceAllocation) obj; + return Objects.equals(this.mplsLabel, other.mplsLabel); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("mplsLabel", mplsLabel) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java new file mode 100644 index 00000000..0a03f450 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/MplsLabelResourceRequest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014-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.link; + +import com.google.common.base.MoreObjects; +import org.onosproject.net.resource.ResourceRequest; +import org.onosproject.net.resource.ResourceType; + +/** + * Representation of a request for lambda resource. + */ +public class MplsLabelResourceRequest implements ResourceRequest { + + @Override + public ResourceType type() { + return ResourceType.MPLS_LABEL; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/package-info.java new file mode 100644 index 00000000..b10e4ba4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/link/package-info.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +/** + * Services for reserving links and their capacity as network resources, + * e.g. bandwidth, lambdas. + */ +package org.onosproject.net.resource.link; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/package-info.java new file mode 100644 index 00000000..e676fc87 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/resource/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Abstractions for reserving network resources. + */ +package org.onosproject.net.resource; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/DefaultLoad.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/DefaultLoad.java new file mode 100644 index 00000000..45e85372 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/DefaultLoad.java @@ -0,0 +1,111 @@ +/* + * Copyright 2014 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 com.google.common.base.MoreObjects; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Implementation of a load. + */ +public class DefaultLoad implements Load { + + private final boolean isValid; + private final long current; + private final long previous; + private final long time; + private final long interval; + + /** + * Indicates the flow statistics poll interval in seconds. + */ + private static long pollInterval = 10; + + /** + * Creates an invalid load. + */ + public DefaultLoad() { + this.isValid = false; + this.time = System.currentTimeMillis(); + this.current = -1; + this.previous = -1; + this.interval = pollInterval; + } + + /** + * Creates a load value from the parameters. + * + * @param current the current value + * @param previous the previous value + */ + public DefaultLoad(long current, long previous) { + this(current, previous, pollInterval); + } + + /** + * Creates a load value from the parameters. + * + * @param current the current value + * @param previous the previous value + * @param interval poll interval for this load + */ + public DefaultLoad(long current, long previous, long interval) { + checkArgument(interval > 0, "Interval must be greater than 0"); + this.current = current; + this.previous = previous; + this.time = System.currentTimeMillis(); + this.isValid = true; + this.interval = interval; + } + + /** + * Sets the poll interval in seconds. Used solely for the purpose of + * computing the load. + * + * @param newPollInterval poll interval duration in seconds + */ + public static void setPollInterval(long newPollInterval) { + pollInterval = newPollInterval; + } + + @Override + public long rate() { + return (current - previous) / interval; + } + + @Override + public long latest() { + return current; + } + + @Override + public boolean isValid() { + return isValid; + } + + @Override + public long time() { + return time; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper("Load").add("rate", rate()) + .add("latest", latest()).toString(); + + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/Load.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/Load.java new file mode 100644 index 00000000..38fed04e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/Load.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014 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; + +/** + * Simple data repository for link load information. + */ +public interface Load { + + /** + * Obtain the current observed rate (in bytes/s) on a link. + * + * @return long value + */ + long rate(); + + /** + * Obtain the latest bytes counter viewed on that link. + * + * @return long value + */ + long latest(); + + /** + * Indicates whether this load was built on valid values. + * + * @return boolean + */ + boolean isValid(); + + /** + * Returns when this value was seen. + * + * @return epoch time + */ + long time(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/StatisticService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/StatisticService.java new file mode 100644 index 00000000..b9f7cc91 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/StatisticService.java @@ -0,0 +1,85 @@ +/* + * Copyright 2014 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.core.ApplicationId; +import org.onosproject.core.GroupId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.flow.FlowRule; + +import java.util.Optional; + +/** + * Service for obtaining statistic information about link in the system. + * Statistics are obtained from the FlowRuleService in order to minimize the + * amount of hammering occuring at the dataplane. + */ +public interface StatisticService { + + /** + * Obtain the load for a the ingress to the given link. + * + * @param link the link to query. + * @return a {@link org.onosproject.net.statistic.Load Load} + */ + Load load(Link link); + + /** + * Obtain the load for the given port. + * + * @param connectPoint the port to query + * @return a {@link org.onosproject.net.statistic.Load} + */ + Load load(ConnectPoint connectPoint); + + /** + * Find the most loaded link along a path. + * + * @param path the path to search in + * @return the most loaded {@link org.onosproject.net.Link}. + */ + Link max(Path path); + + /** + * Find the least loaded link along a path. + * + * @param path the path to search in + * @return the least loaded {@link org.onosproject.net.Link}. + */ + Link min(Path path); + + /** + * Returns the highest hitter (a flow rule) for a given port, ie. the + * flow rule which is generating the most load. + * + * @param connectPoint the port + * @return the flow rule + */ + FlowRule highestHitter(ConnectPoint connectPoint); + + /** + * Obtain the load for a the ingress to the given link used by + * the specified application ID and group ID. + * + * @param link link to query + * @param appId application ID to filter with + * @param groupId group ID to filter with + * @return {@link Load Load} + */ + Load load(Link link, ApplicationId appId, Optional groupId); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/StatisticStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/StatisticStore.java new file mode 100644 index 00000000..8566ef5b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/StatisticStore.java @@ -0,0 +1,65 @@ +/* + * Copyright 2014 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; + +/** + * Store to house the computed statistics. + */ +public interface StatisticStore { + + /** + * Lay the foundation for receiving flow stats for this rule. + * + * @param rule a {@link org.onosproject.net.flow.FlowRule} + */ + void prepareForStatistics(FlowRule rule); + + /** + * Remove entries associated with this rule. + * + * @param rule {@link org.onosproject.net.flow.FlowRule} + */ + void removeFromStatistics(FlowRule rule); + + /** + * Adds a stats observation for a flow rule. + * + * @param rule a {@link org.onosproject.net.flow.FlowEntry} + */ + void addOrUpdateStatistic(FlowEntry rule); + + /** + * Fetches the current observed stats values. + * + * @param connectPoint the port to fetch information for + * @return set of current flow rules + */ + Set getCurrentStatistic(ConnectPoint connectPoint); + + /** + * Fetches the current observed stats values. + * + * @param connectPoint the port to fetch information for + * @return set of current values + */ + Set getPreviousStatistic(ConnectPoint connectPoint); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/package-info.java new file mode 100644 index 00000000..37889f3d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/statistic/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Service for looking up statistics on links. + */ +package org.onosproject.net.statistic; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/ClusterId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/ClusterId.java new file mode 100644 index 00000000..676f0068 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/ClusterId.java @@ -0,0 +1,76 @@ +/* + * Copyright 2014 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 java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Representation of the topology cluster identity. + */ +public final class ClusterId { + + private final int id; + + // Public construction is prohibit + private ClusterId(int id) { + this.id = id; + } + + /** + * Returns the cluster identifier, represented by the specified integer + * serial number. + * + * @param id integer serial number + * @return cluster identifier + */ + public static ClusterId clusterId(int id) { + return new ClusterId(id); + } + + /** + * Returns the backing integer index. + * + * @return backing integer index + */ + public int index() { + return id; + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ClusterId) { + final ClusterId other = (ClusterId) obj; + return Objects.equals(this.id, other.id); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this).add("id", id).toString(); + } + +} 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 new file mode 100644 index 00000000..f1e20dac --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultGraphDescription.java @@ -0,0 +1,141 @@ +/* + * Copyright 2014-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 com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import org.onosproject.net.AbstractDescription; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.SparseAnnotations; +import org.slf4j.Logger; + +import java.util.Map; + +import static com.google.common.base.Preconditions.checkArgument; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Default implementation of an immutable topology graph data carrier. + */ +public class DefaultGraphDescription extends AbstractDescription + implements GraphDescription { + + private static final Logger log = getLogger(DefaultGraphDescription.class); + + private final long nanos; + private final long creationTime; + private final ImmutableSet vertexes; + private final ImmutableSet edges; + + 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. + * + * @param nanos time in nanos of when the topology description was created + * @param millis time in millis 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 + */ + public DefaultGraphDescription(long nanos, long millis, + Iterable devices, + Iterable links, + SparseAnnotations... annotations) { + super(annotations); + this.nanos = nanos; + this.creationTime = millis; + this.vertexes = buildVertexes(devices); + this.edges = buildEdges(links); + vertexesById.clear(); + } + + @Override + public long timestamp() { + return nanos; + } + + @Override + public long creationTime() { + return creationTime; + } + + @Override + public ImmutableSet vertexes() { + return vertexes; + } + + @Override + public ImmutableSet edges() { + return edges; + } + + // Builds a set of topology vertexes from the specified list of devices + private ImmutableSet buildVertexes(Iterable devices) { + ImmutableSet.Builder vertexes = ImmutableSet.builder(); + for (Device device : devices) { + TopologyVertex vertex = new DefaultTopologyVertex(device.id()); + vertexes.add(vertex); + vertexesById.put(vertex.deviceId(), vertex); + } + return vertexes.build(); + } + + // Builds a set of topology vertexes from the specified list of links + private ImmutableSet buildEdges(Iterable links) { + ImmutableSet.Builder edges = ImmutableSet.builder(); + for (Link link : links) { + try { + edges.add(new DefaultTopologyEdge(vertexOf(link.src()), + vertexOf(link.dst()), + link)); + } catch (IllegalArgumentException e) { + log.debug("Ignoring {}, missing vertex", link); + } + } + return edges.build(); + } + + // Fetches a vertex corresponding to the given connection point device. + private TopologyVertex vertexOf(ConnectPoint connectPoint) { + DeviceId id = connectPoint.deviceId(); + TopologyVertex vertex = vertexesById.get(id); + checkArgument(vertex != null, "Vertex missing for %s", id); + return vertex; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultTopologyCluster.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultTopologyCluster.java new file mode 100644 index 00000000..ac32316c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultTopologyCluster.java @@ -0,0 +1,97 @@ +/* + * Copyright 2014-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 java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Default implementation of a network topology cluster. + */ +public class DefaultTopologyCluster implements TopologyCluster { + + private final ClusterId id; + private final int deviceCount; + private final int linkCount; + private final TopologyVertex root; + + /** + * Creates a new topology cluster descriptor with the specified attributes. + * + * @param id cluster id + * @param deviceCount number of devices in the cluster + * @param linkCount number of links in the cluster + * @param root cluster root node + */ + public DefaultTopologyCluster(ClusterId id, int deviceCount, int linkCount, + TopologyVertex root) { + this.id = id; + this.deviceCount = deviceCount; + this.linkCount = linkCount; + this.root = root; + } + + @Override + public ClusterId id() { + return id; + } + + @Override + public int deviceCount() { + return deviceCount; + } + + @Override + public int linkCount() { + return linkCount; + } + + @Override + public TopologyVertex root() { + return root; + } + + @Override + public int hashCode() { + return Objects.hash(id, deviceCount, linkCount, root); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultTopologyCluster) { + final DefaultTopologyCluster other = (DefaultTopologyCluster) obj; + return Objects.equals(this.id, other.id) && + Objects.equals(this.deviceCount, other.deviceCount) && + Objects.equals(this.linkCount, other.linkCount) && + Objects.equals(this.root, other.root); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("id", id) + .add("deviceCount", deviceCount) + .add("linkCount", linkCount) + .add("root", root) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultTopologyEdge.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultTopologyEdge.java new file mode 100644 index 00000000..dacb5fd8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultTopologyEdge.java @@ -0,0 +1,84 @@ +/* + * Copyright 2014 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.Link; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Implementation of the topology edge backed by a link. + */ +public class DefaultTopologyEdge implements TopologyEdge { + + private final Link link; + private final TopologyVertex src; + private final TopologyVertex dst; + + /** + * Creates a new topology edge. + * + * @param src source vertex + * @param dst destination vertex + * @param link infrastructure link + */ + public DefaultTopologyEdge(TopologyVertex src, TopologyVertex dst, Link link) { + this.src = src; + this.dst = dst; + this.link = link; + } + + @Override + public Link link() { + return link; + } + + @Override + public TopologyVertex src() { + return src; + } + + @Override + public TopologyVertex dst() { + return dst; + } + + @Override + public int hashCode() { + return Objects.hash(link); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultTopologyEdge) { + final DefaultTopologyEdge other = (DefaultTopologyEdge) obj; + return Objects.equals(this.link, other.link); + } + return false; + } + + @Override + public String toString() { + return toStringHelper(this).add("src", src).add("dst", dst).toString(); + } + +} + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultTopologyVertex.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultTopologyVertex.java new file mode 100644 index 00000000..07a09cbd --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/DefaultTopologyVertex.java @@ -0,0 +1,66 @@ +/* + * Copyright 2014 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.DeviceId; + +import java.util.Objects; + +/** + * Implementation of the topology vertex backed by a device id. + */ +public class DefaultTopologyVertex implements TopologyVertex { + + private final DeviceId deviceId; + + /** + * Creates a new topology vertex. + * + * @param deviceId backing infrastructure device identifier + */ + public DefaultTopologyVertex(DeviceId deviceId) { + this.deviceId = deviceId; + } + + @Override + public DeviceId deviceId() { + return deviceId; + } + + @Override + public int hashCode() { + return Objects.hash(deviceId); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DefaultTopologyVertex) { + final DefaultTopologyVertex other = (DefaultTopologyVertex) obj; + return Objects.equals(this.deviceId, other.deviceId); + } + return false; + } + + @Override + public String toString() { + return deviceId.toString(); + } + +} + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/GraphDescription.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/GraphDescription.java new file mode 100644 index 00000000..806a5a45 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/GraphDescription.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014-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.Description; + +import com.google.common.collect.ImmutableSet; + +/** + * Describes attribute(s) of a network graph. + */ +public interface GraphDescription extends Description { + + /** + * Returns the creation timestamp of the graph description. This is + * expressed in system nanos to allow proper sequencing. + * + * @return graph description creation timestamp + */ + long timestamp(); + + /** + * Returns the creation timestamp of the graph description. This is + * expressed in system millis to allow proper date and time formatting. + * + * @return graph description creation timestamp in millis + */ + long creationTime(); + + /** + * Returns the set of topology graph vertexes. + * + * @return set of graph vertexes + */ + ImmutableSet vertexes(); + + /** + * Returns the set of topology graph edges. + * + * @return set of graph edges + */ + ImmutableSet edges(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/LinkWeight.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/LinkWeight.java new file mode 100644 index 00000000..a19abd40 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/LinkWeight.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 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.onlab.graph.EdgeWeight; + +/** + * Entity capable of determining cost or weight of a specified topology + * graph edge. + */ +public interface LinkWeight extends EdgeWeight { +} 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 new file mode 100644 index 00000000..be8c7cfc --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/PathService.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014 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.ElementId; +import org.onosproject.net.Path; + +import java.util.Set; + +/** + * Service for obtaining pre-computed paths or for requesting computation of + * paths using the current topology snapshot. + */ +public interface PathService { + + /** + * Returns the set of all shortest paths, precomputed in terms of hop-count, + * between the specified source and destination elements. + * + * @param src source element + * @param dst destination element + * @return set of all shortest paths between the two elements + */ + Set getPaths(ElementId src, ElementId dst); + + /** + * Returns the set of all shortest paths, computed using the supplied + * edge-weight entity, between the specified source and destination + * network elements. + * + * @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); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/Topology.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/Topology.java new file mode 100644 index 00000000..6337807c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/Topology.java @@ -0,0 +1,71 @@ +/* + * Copyright 2014-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.Provided; + +/** + * Represents a network topology computation snapshot. + */ +public interface Topology extends Provided { + + /** + * Returns the time, specified in system nanos of when the topology became + * available. + * + * @return time in system nanos + */ + long time(); + + /** + * Returns the time, specified in system millis of when the topology became + * available. + * + * @return time in system nanos + */ + long creationTime(); + + /** + * Returns the time, specified in system nanos of how long the topology took + * to compute. + * + * @return elapsed time in system nanos + */ + long computeCost(); + + /** + * Returns the number of SCCs (strongly connected components) in the + * topology. + * + * @return number of clusters + */ + int clusterCount(); + + /** + * Returns the number of infrastructure devices in the topology. + * + * @return number of devices + */ + int deviceCount(); + + /** + * Returns the number of infrastructure links in the topology. + * + * @return number of links + */ + int linkCount(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyCluster.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyCluster.java new file mode 100644 index 00000000..8e685534 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyCluster.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014-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; + +/** + * Representation of an SCC (strongly-connected component) in a network topology. + */ +public interface TopologyCluster { + + /** + * Returns the cluster id. + * + * @return cluster identifier + */ + ClusterId id(); + + /** + * Returns the number of devices in the cluster. + * + * @return number of cluster devices + */ + int deviceCount(); + + /** + * Returns the number of infrastructure links in the cluster. + * + * @return number of cluster links + */ + int linkCount(); + + /** + * Returns the cluster root vertex. + * + * @return cluster root vertex + */ + TopologyVertex root(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyEdge.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyEdge.java new file mode 100644 index 00000000..008c8c44 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyEdge.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 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.onlab.graph.Edge; +import org.onosproject.net.Link; + +/** + * Represents an edge in the topology graph. + */ +public interface TopologyEdge extends Edge { + + /** + * Returns the associated infrastructure link. + * + * @return backing infrastructure link + */ + Link link(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyEvent.java new file mode 100644 index 00000000..10c8dfc3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyEvent.java @@ -0,0 +1,78 @@ +/* + * Copyright 2014 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.event.AbstractEvent; +import org.onosproject.event.Event; + +import java.util.List; + +/** + * Describes network topology event. + */ +public class TopologyEvent extends AbstractEvent { + + private final List reasons; + + /** + * Type of topology events. + */ + public enum Type { + /** + * Signifies that topology has changed. + */ + TOPOLOGY_CHANGED + } + + /** + * Creates an event of a given type and for the specified topology and the + * current time. + * + * @param type topology event type + * @param topology event topology subject + * @param reasons list of events that triggered topology change + */ + public TopologyEvent(Type type, Topology topology, List reasons) { + super(type, topology); + this.reasons = reasons; + } + + /** + * Creates an event of a given type and for the specified topology and time. + * + * @param type link event type + * @param topology event topology subject + * @param reasons list of events that triggered topology change + * @param time occurrence time + */ + public TopologyEvent(Type type, Topology topology, List reasons, + long time) { + super(type, topology, time); + this.reasons = reasons; + } + + + /** + * Returns the list of events that triggered the topology change. + * + * @return list of events responsible for change in topology; null if + * initial topology computation + */ + public List reasons() { + return reasons; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyGraph.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyGraph.java new file mode 100644 index 00000000..f3565fa4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyGraph.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 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.onlab.graph.Graph; + +/** + * Represents an immutable topology graph. + */ +public interface TopologyGraph extends Graph { + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyListener.java new file mode 100644 index 00000000..625587b0 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyListener.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.event.EventListener; + +/** + * Entity capable of receiving network topology related events. + */ +public interface TopologyListener extends EventListener { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyProvider.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyProvider.java new file mode 100644 index 00000000..f52b798b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyProvider.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014 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.provider.Provider; + +/** + * Means for injecting topology information into the core. + */ +public interface TopologyProvider extends Provider { + + /** + * Triggers topology recomputation. + */ + void triggerRecompute(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyProviderRegistry.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyProviderRegistry.java new file mode 100644 index 00000000..15eeed45 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyProviderRegistry.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 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.provider.ProviderRegistry; + +/** + * Abstraction of a network topology provider registry. + */ +public interface TopologyProviderRegistry extends + ProviderRegistry { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyProviderService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyProviderService.java new file mode 100644 index 00000000..742110a2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyProviderService.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 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.event.Event; +import org.onosproject.net.provider.ProviderService; + +import java.util.List; + +/** + * Means for injecting topology information into the core. + */ +public interface TopologyProviderService extends ProviderService { + + /** + * Signals the core that some aspect of the topology has changed. + * + * @param graphDescription information about the network graph + * @param reasons events that triggered topology change + */ + void topologyChanged(GraphDescription graphDescription, + List reasons); + +} 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 new file mode 100644 index 00000000..41eac2c4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyService.java @@ -0,0 +1,135 @@ +/* + * Copyright 2014 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.event.ListenerService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Path; + +import java.util.Set; + +/** + * Service for providing network topology information. + */ +public interface TopologyService + extends ListenerService { + + /** + * Returns the current topology descriptor. + * + * @return current topology + */ + Topology currentTopology(); + + /** + * Indicates whether the specified topology is the latest or not. + * + * @param topology topology descriptor + * @return true if the topology is the most recent; false otherwise + */ + boolean isLatest(Topology topology); + + /** + * Returns the graph view of the specified topology. + * + * @param topology topology descriptor + * @return topology graph view + */ + TopologyGraph getGraph(Topology topology); + + /** + * Returns the set of clusters in the specified topology. + * + * @param topology topology descriptor + * @return set of topology clusters + */ + Set getClusters(Topology topology); + + /** + * Returns the cluster with the specified ID. + * + * @param topology topology descriptor + * @param clusterId cluster identifier + * @return topology cluster + */ + TopologyCluster getCluster(Topology topology, ClusterId clusterId); + + /** + * Returns the set of devices that belong to the specified cluster. + * + * @param topology topology descriptor + * @param cluster topology cluster + * @return set of cluster devices + */ + Set getClusterDevices(Topology topology, TopologyCluster cluster); + + /** + * Returns the set of links that form the specified cluster. + * + * @param topology topology descriptor + * @param cluster topology cluster + * @return set of cluster links + */ + Set getClusterLinks(Topology topology, TopologyCluster cluster); + + /** + * Returns the set of all shortest paths, 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 getPaths(Topology topology, DeviceId src, DeviceId dst); + + /** + * Returns the set of all shortest paths, 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 getPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight); + + /** + * Indicates whether the specified connection point is part of the network + * infrastructure or part of network edge. + * + * @param topology topology descriptor + * @param connectPoint connection point + * @return true of connection point is in infrastructure; false if edge + */ + boolean isInfrastructure(Topology topology, ConnectPoint connectPoint); + + + /** + * Indicates whether broadcast is allowed for traffic received on the + * specified connection point. + * + * @param topology topology descriptor + * @param connectPoint connection point + * @return true if broadcast is permissible + */ + boolean isBroadcastPoint(Topology topology, ConnectPoint connectPoint); + +} 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 new file mode 100644 index 00000000..983e616e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStore.java @@ -0,0 +1,144 @@ +/* + * Copyright 2014 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.event.Event; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.store.Store; + +import java.util.List; +import java.util.Set; + +/** + * Manages inventory of topology snapshots; not intended for direct use. + */ +public interface TopologyStore extends Store { + + /** + * Returns the current topology snapshot. + * + * @return current topology descriptor + */ + Topology currentTopology(); + + /** + * Indicates whether the topology is the latest. + * + * @param topology topology descriptor + * @return true if topology is the most recent one + */ + boolean isLatest(Topology topology); + + /** + * Returns the immutable graph view of the current topology. + * + * @param topology topology descriptor + * @return graph view + */ + TopologyGraph getGraph(Topology topology); + + /** + * Returns the set of topology SCC clusters. + * + * @param topology topology descriptor + * @return set of clusters + */ + Set getClusters(Topology topology); + + /** + * Returns the cluster of the specified topology. + * + * @param topology topology descriptor + * @param clusterId cluster identity + * @return topology cluster + */ + TopologyCluster getCluster(Topology topology, ClusterId clusterId); + + /** + * Returns the cluster of the specified topology. + * + * @param topology topology descriptor + * @param cluster topology cluster + * @return set of cluster links + */ + Set getClusterDevices(Topology topology, TopologyCluster cluster); + + /** + * Returns the cluster of the specified topology. + * + * @param topology topology descriptor + * @param cluster topology cluster + * @return set of cluster links + */ + Set getClusterLinks(Topology topology, TopologyCluster cluster); + + /** + * Returns the set of pre-computed shortest paths between src and dest. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @return set of shortest paths + */ + Set getPaths(Topology topology, DeviceId src, DeviceId dst); + + /** + * Computes and returns the set of shortest paths between src and dest. + * + * @param topology topology descriptor + * @param src source device + * @param dst destination device + * @param weight link weight function + * @return set of shortest paths + */ + Set getPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight); + + /** + * Indicates whether the given connect point is part of the network fabric. + * + * @param topology topology descriptor + * @param connectPoint connection point + * @return true if infrastructure; false otherwise + */ + boolean isInfrastructure(Topology topology, ConnectPoint connectPoint); + + /** + * Indicates whether broadcast is allowed for traffic received on the + * given connection point. + * + * @param topology topology descriptor + * @param connectPoint connection point + * @return true if broadcast allowed; false otherwise + */ + boolean isBroadcastPoint(Topology topology, ConnectPoint connectPoint); + + /** + * Generates a new topology snapshot from the specified description. + * + * @param providerId provider identification + * @param graphDescription topology graph description + * @param reasons list of events that triggered the update + * @return topology update event or null if the description is old + */ + TopologyEvent updateTopology(ProviderId providerId, + GraphDescription graphDescription, + List reasons); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStoreDelegate.java new file mode 100644 index 00000000..c425970b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyStoreDelegate.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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.store.StoreDelegate; + +/** + * Topology store delegate abstraction. + */ +public interface TopologyStoreDelegate extends StoreDelegate { +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyVertex.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyVertex.java new file mode 100644 index 00000000..9f37dcb4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/TopologyVertex.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 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.onlab.graph.Vertex; +import org.onosproject.net.DeviceId; + +/** + * Represents a vertex in the topology graph. + */ +public interface TopologyVertex extends Vertex { + + /** + * Returns the associated infrastructure device identification. + * + * @return device identifier + */ + DeviceId deviceId(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/package-info.java new file mode 100644 index 00000000..3cd6ceb8 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/net/topology/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Network topology model & related services API definitions. + */ +package org.onosproject.net.topology; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/rest/AbstractApiDocRegistrator.java b/framework/src/onos/core/api/src/main/java/org/onosproject/rest/AbstractApiDocRegistrator.java new file mode 100644 index 00000000..7349c69e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/rest/AbstractApiDocRegistrator.java @@ -0,0 +1,53 @@ +/* + * 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.rest; + +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; + +/** + * Self-registering REST API provider. + */ +@Component(immediate = true, componentAbstract = true) +public abstract class AbstractApiDocRegistrator { + + protected final ApiDocProvider provider; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ApiDocService service; + + /** + * Creates registrator for the specified REST API doc provider. + * + * @param provider REST API provider + */ + protected AbstractApiDocRegistrator(ApiDocProvider provider) { + this.provider = provider; + } + + @Activate + protected void activate() { + service.register(provider); + } + + @Deactivate + protected void deactivate() { + service.unregister(provider); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/rest/AbstractInjectionResource.java b/framework/src/onos/core/api/src/main/java/org/onosproject/rest/AbstractInjectionResource.java new file mode 100644 index 00000000..de182f03 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/rest/AbstractInjectionResource.java @@ -0,0 +1,78 @@ +/* + * 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.rest; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * Resource for serving semi-static resources. + */ +public class AbstractInjectionResource extends AbstractWebResource { + + /** + * Returns the index into the supplied string where the end of the + * specified pattern is located. + * + * @param string string to split + * @param start index where to start looking for pattern + * @param stopPattern optional pattern where to stop + * @return index where the split should occur + */ + protected int split(String string, int start, String stopPattern) { + int i = stopPattern != null ? string.indexOf(stopPattern, start) : string.length(); + checkArgument(i >= 0, "Unable to locate pattern %s", stopPattern); + return i + (stopPattern != null ? stopPattern.length() : 0); + } + + /** + * Produces an input stream from the bytes of the specified sub-string. + * + * @param string source string + * @param start index where to start stream + * @param end index where to end stream + * @return input stream + */ + protected InputStream stream(String string, int start, int end) { + return new ByteArrayInputStream(string.substring(start, end).getBytes()); + } + + /** + * Auxiliary enumeration to sequence input streams. + */ + protected class StreamEnumeration implements Enumeration { + private final Iterator iterator; + + public StreamEnumeration(List streams) { + this.iterator = streams.iterator(); + } + + @Override + public boolean hasMoreElements() { + return iterator.hasNext(); + } + + @Override + public InputStream nextElement() { + return iterator.next(); + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/rest/AbstractWebResource.java b/framework/src/onos/core/api/src/main/java/org/onosproject/rest/AbstractWebResource.java new file mode 100644 index 00000000..d3249ba5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/rest/AbstractWebResource.java @@ -0,0 +1,98 @@ +/* + * Copyright 2014-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.rest; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onlab.rest.BaseResource; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.CodecService; +import org.onosproject.codec.JsonCodec; + +/** + * Abstract REST resource. + */ +public class AbstractWebResource extends BaseResource implements CodecContext { + + private final ObjectMapper mapper = new ObjectMapper(); + + @Override + public ObjectMapper mapper() { + return mapper; + } + + /** + * Returns the JSON codec for the specified entity class. + * + * @param entityClass entity class + * @param entity type + * @return JSON codec + */ + public JsonCodec codec(Class entityClass) { + return get(CodecService.class).getCodec(entityClass); + } + + /** + * Returns JSON object wrapping the array encoding of the specified + * collection of items. + * + * @param codecClass codec item class + * @param field field holding the array + * @param items collection of items to be encoded into array + * @param item type + * @return JSON object + */ + protected ObjectNode encodeArray(Class codecClass, String field, + Iterable items) { + ObjectNode result = mapper().createObjectNode(); + result.set(field, codec(codecClass).encode(items, this)); + return result; + } + + @Override + public T getService(Class serviceClass) { + return get(serviceClass); + } + + /** + * Creates and returns a new child object within the specified parent and + * bound to the given key. + * + * @param parent parent object + * @param key key for the new child object + * @return child object + */ + public ObjectNode newObject(ObjectNode parent, String key) { + ObjectNode node = mapper.createObjectNode(); + parent.set(key, node); + return node; + } + + /** + * Creates and returns a new child array within the specified parent and + * bound to the given key. + * + * @param parent parent object + * @param key key for the new child array + * @return child array + */ + public ArrayNode newArray(ObjectNode parent, String key) { + ArrayNode node = mapper.createArrayNode(); + parent.set(key, node); + return node; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/rest/ApiDocProvider.java b/framework/src/onos/core/api/src/main/java/org/onosproject/rest/ApiDocProvider.java new file mode 100644 index 00000000..50cac4cd --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/rest/ApiDocProvider.java @@ -0,0 +1,98 @@ +/* + * 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.rest; + +import com.google.common.annotations.Beta; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Entity capable of providing REST API documentation resources. + */ +@Beta +public class ApiDocProvider { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private static final String DOCS = "/apidoc/swagger.json"; + private static final String MODEL = "/apidoc/model.json"; + + private final String key; + private final String name; + private final ClassLoader classLoader; + + /** + * Creates a new REST API documentation provider. + * + * @param key REST API key + * @param name REST API name + * @param classLoader class loader + */ + public ApiDocProvider(String key, String name, ClassLoader classLoader) { + this.key = checkNotNull(key, "Key cannot be null"); + this.name = checkNotNull(name, "Name cannot be null"); + this.classLoader = checkNotNull(classLoader, "Class loader cannot be null"); + } + + /** + * Returns the REST API key. + * + * @return REST API key + */ + public String key() { + return key; + } + + /** + * Returns the REST API name. + * + * @return REST API name + */ + public String name() { + return name; + } + + /** + * Returns input stream containing Swagger UI compatible JSON. + * + * @return input stream with Swagger JSON data + */ + public InputStream docs() { + return get(DOCS); + } + + /** + * Returns input stream containing JSON model schema. + * + * @return input stream with JSON model schema + */ + public InputStream model() { + return get(MODEL); + } + + private InputStream get(String resource) { + InputStream stream = classLoader.getResourceAsStream(resource); + if (stream == null) { + log.warn("Unable to find JSON resource {}", resource); + } + return stream; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/rest/ApiDocService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/rest/ApiDocService.java new file mode 100644 index 00000000..f7268532 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/rest/ApiDocService.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.rest; + +import com.google.common.annotations.Beta; + +import java.util.Set; + +/** + * Service for registering REST API documentation resources. + */ +@Beta +public interface ApiDocService { + + /** + * Registers the specified REST API documentation provider. + * + * @param provider REST API documentation provider + */ + void register(ApiDocProvider provider); + + /** + * Unregisters the specified REST API documentation provider. + * + * @param provider REST API documentation provider + */ + void unregister(ApiDocProvider provider); + + /** + * Returns the set of all registered REST API documentation providers. + * + * @return set of registered documentation providers + */ + Set getDocProviders(); + + /** + * Returns the specified REST API documentation provider with the specified + * key. + * + * @param key REST API key + * @return documentation provider + */ + ApiDocProvider getDocProvider(String key); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/rest/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/rest/package-info.java new file mode 100644 index 00000000..15e5d20d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/rest/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. + */ + +/** + * Base abstractions and utilities for developing REST APIs. + */ +package org.onosproject.rest; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/security/AppGuard.java b/framework/src/onos/core/api/src/main/java/org/onosproject/security/AppGuard.java new file mode 100644 index 00000000..800135f4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/security/AppGuard.java @@ -0,0 +1,38 @@ +/* + * 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.security; + + +/** + * Aids SM-ONOS to perform API-level permission checking. + */ +public final class AppGuard { + + private AppGuard() { + } + + /** + * Checks if the caller has the required permission only when security-mode is enabled. + * @param permission permission to be checked + */ + public static void checkPermission(AppPermission.Type permission) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + System.getSecurityManager().checkPermission(new AppPermission(permission)); + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/security/AppPermission.java b/framework/src/onos/core/api/src/main/java/org/onosproject/security/AppPermission.java new file mode 100644 index 00000000..21a70d2b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/security/AppPermission.java @@ -0,0 +1,110 @@ +/* + * 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.security; + +import java.security.BasicPermission; + +/** + * Implementation of API access permission. + */ +public class AppPermission extends BasicPermission { + + public enum Type { + APP_READ, + APP_EVENT, + CONFIG_READ, + CONFIG_WRITE, + CLUSTER_READ, + CLUSTER_WRITE, + CLUSTER_EVENT, + DEVICE_READ, + DEVICE_EVENT, + DRIVER_READ, + DRIVER_WRITE, + FLOWRULE_READ, + FLOWRULE_WRITE, + FLOWRULE_EVENT, + GROUP_READ, + GROUP_WRITE, + GROUP_EVENT, + HOST_READ, + HOST_WRITE, + HOST_EVENT, + INTENT_READ, + INTENT_WRITE, + INTENT_EVENT, + LINK_READ, + LINK_WRITE, + LINK_EVENT, + PACKET_READ, + PACKET_WRITE, + PACKET_EVENT, + STATISTIC_READ, + TOPOLOGY_READ, + TOPOLOGY_EVENT, + TUNNEL_READ, + TUNNEL_WRITE, + TUNNEL_EVENT, + STORAGE_WRITE + } + + protected Type type; + /** + * Creates new application permission using the supplied data. + * @param name permission name + */ + public AppPermission(String name) { + super(name.toUpperCase(), ""); + try { + type = Type.valueOf(name); + } catch (IllegalArgumentException e) { + type = null; + } + } + + /** + * Creates new application permission using the supplied data. + * @param name permission name + * @param actions permission action + */ + public AppPermission(String name, String actions) { + super(name.toUpperCase(), actions); + try { + type = Type.valueOf(name); + } catch (IllegalArgumentException e) { + type = null; + } + } + + /** + * Crates new application permission using the supplied data. + * @param type permission type + */ + public AppPermission(Type type) { + super(type.name(), ""); + this.type = type; + } + + /** + * Returns type of permission. + * @return application permission type + */ + public Type getType() { + return this.type; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/security/Permission.java b/framework/src/onos/core/api/src/main/java/org/onosproject/security/Permission.java new file mode 100644 index 00000000..75d9433f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/security/Permission.java @@ -0,0 +1,77 @@ +/* + * 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.security; + +public class Permission { + + protected String classname; + protected String name; + protected String actions; + + public Permission(String classname, String name, String actions) { + this.classname = classname; + this.name = name; + if (actions == null) { + this.actions = ""; + } else { + this.actions = actions; + } + } + + public Permission(String classname, String name) { + this.classname = classname; + this.name = name; + this.actions = ""; + } + + public String getClassName() { + return classname; + } + + public String getName() { + return name; + } + + public String getActions() { + return actions; + } + + @Override + public int hashCode() { + return 0; + } + + @Override + public boolean equals(Object thatPerm) { + if (this == thatPerm) { + return true; + } + + if (!(thatPerm instanceof Permission)) { + return false; + } + + Permission that = (Permission) thatPerm; + return (this.classname.equals(that.classname)) && (this.name.equals(that.name)) + && (this.actions.equals(that.actions)); + } + + @Override + public String toString() { + return String.format("(%s, %s, %s)", classname, name, actions); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/security/SecurityAdminService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/security/SecurityAdminService.java new file mode 100644 index 00000000..16ea94d1 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/security/SecurityAdminService.java @@ -0,0 +1,77 @@ +/* + * 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.security; + +import org.onosproject.core.ApplicationId; + +import java.security.Permission; +import java.util.List; +import java.util.Map; + +/** + * Security-Mode ONOS service. + */ +public interface SecurityAdminService { + + /** + * Returns true if security policy has been enforced to specified application. + * @param appId application identifier + * @return true if secured. + */ + boolean isSecured(ApplicationId appId); + + /** + * Changes SecurityModeState of specified application to REVIEWED. + * @param appId application identifier + */ + void review(ApplicationId appId); + + /** + * Accepts and enforces security policy to specified application. + * @param appId application identifier + */ + void acceptPolicy(ApplicationId appId); + + /** + * Register application to SM-ONOS subsystem. + * @param appId application identifier + */ + void register(ApplicationId appId); + + /** + * Returns sorted developer specified permission Map. + * @param appId application identifier + * @return Map of list of permissions sorted by permission type + */ + Map> getPrintableSpecifiedPermissions(ApplicationId appId); + + /** + * Returns sorted granted permission Map. + * @param appId application identifier + * @return Map of list of permissions sorted by permission type + */ + Map> getPrintableGrantedPermissions(ApplicationId appId); + + /** + * Returns sorted requested permission Map. + * @param appId application identifier + * @return Map of list of permissions sorted by permission type + */ + Map> getPrintableRequestedPermissions(ApplicationId appId); + + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/security/SecurityUtil.java b/framework/src/onos/core/api/src/main/java/org/onosproject/security/SecurityUtil.java new file mode 100644 index 00000000..34b4e78a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/security/SecurityUtil.java @@ -0,0 +1,82 @@ +/* + * 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.security; + +import org.onlab.osgi.DefaultServiceDirectory; +import org.onlab.osgi.ServiceDirectory; +import org.onlab.osgi.ServiceNotFoundException; +import org.onosproject.core.ApplicationId; + +/** + * Utility class to aid Security-Mode ONOS. + */ +public final class SecurityUtil { + + protected static ServiceDirectory serviceDirectory = new DefaultServiceDirectory(); + + private SecurityUtil() { + } + + public static boolean isSecurityModeEnabled() { + if (System.getSecurityManager() != null) { + try { + SecurityAdminService securityService = serviceDirectory.get(SecurityAdminService.class); + if (securityService != null) { + return true; + } + } catch (ServiceNotFoundException e) { + return false; + } + } + return false; + } + + public static SecurityAdminService getSecurityService() { + if (System.getSecurityManager() != null) { + try { + SecurityAdminService securityService = serviceDirectory.get(SecurityAdminService.class); + if (securityService != null) { + return securityService; + } + } catch (ServiceNotFoundException e) { + return null; + } + } + return null; + } + + public static boolean isAppSecured(ApplicationId appId) { + SecurityAdminService service = getSecurityService(); + if (service != null) { + if (!service.isSecured(appId)) { + System.out.println("\n*******************************"); + System.out.println(" SM-ONOS APP WARNING "); + System.out.println("*******************************"); + System.out.println(appId.name() + " has not been secured."); + System.out.println("Please review before activating."); + return false; + } + } + return true; + } + public static void register(ApplicationId appId) { + SecurityAdminService service = getSecurityService(); + if (service != null) { + service.register(appId); + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/security/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/security/package-info.java new file mode 100644 index 00000000..88c3529d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/security/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. + */ + +/** + * Application security constructs. + */ +package org.onosproject.security; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/AbstractStore.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/AbstractStore.java new file mode 100644 index 00000000..a3005e45 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/AbstractStore.java @@ -0,0 +1,72 @@ +/* + * Copyright 2014 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; + +import java.util.List; + +import org.onosproject.event.Event; + +import static com.google.common.base.Preconditions.checkState; + +/** + * Base implementation of a store. + */ +public class AbstractStore> + implements Store { + + protected D delegate; + + @Override + public void setDelegate(D delegate) { + checkState(this.delegate == null || this.delegate == delegate, + "Store delegate already set"); + this.delegate = delegate; + } + + @Override + public void unsetDelegate(D delegate) { + if (this.delegate == delegate) { + this.delegate = null; + } + } + + @Override + public boolean hasDelegate() { + return delegate != null; + } + + /** + * Notifies the delegate with the specified event. + * + * @param event event to delegate + */ + protected void notifyDelegate(E event) { + if (delegate != null) { + delegate.notify(event); + } + } + + /** + * Notifies the delegate with the specified list of events. + * + * @param events list of events to delegate + */ + protected void notifyDelegate(List events) { + for (E event: events) { + notifyDelegate(event); + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/Store.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/Store.java new file mode 100644 index 00000000..8d5b53c4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/Store.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014 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; + +import org.onosproject.event.Event; + +/** + * Abstraction of a entity capable of storing and/or distributing information + * across a cluster. + */ +public interface Store> { + + /** + * Sets the delegate on the store. + * + * @param delegate new store delegate + * @throws java.lang.IllegalStateException if a delegate is already + * currently set on the store and is a different one that + */ + void setDelegate(D delegate); + + /** + * Withdraws the delegate from the store. + * + * @param delegate store delegate to withdraw + * @throws java.lang.IllegalArgumentException if the delegate is not + * currently set on the store + */ + void unsetDelegate(D delegate); + + /** + * Indicates whether the store has a delegate. + * + * @return true if delegate is set + */ + boolean hasDelegate(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/StoreDelegate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/StoreDelegate.java new file mode 100644 index 00000000..71ca8cc0 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/StoreDelegate.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 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; + +import org.onosproject.event.Event; + +/** + * Entity associated with a store and capable of receiving notifications of + * events within the store. + */ +public interface StoreDelegate { + + /** + * Notifies the delegate via the specified event. + * + * @param event store generated event + */ + void notify(E event); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/Timestamp.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/Timestamp.java new file mode 100644 index 00000000..44238ff2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/Timestamp.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014-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; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Opaque version structure. + *

+ * Classes implementing this interface must also implement + * {@link #hashCode()} and {@link #equals(Object)}. + */ +public interface Timestamp extends Comparable { + + @Override + int hashCode(); + + @Override + boolean equals(Object obj); + + /** + * Tests if this timestamp is newer than the specified timestamp. + * + * @param other timestamp to compare against + * @return true if this instance is newer + */ + default boolean isNewerThan(Timestamp other) { + return this.compareTo(checkNotNull(other)) > 0; + } + + /** + * Tests if this timestamp is older than the specified timestamp. + * + * @param other timestamp to compare against + * @return true if this instance is older + */ + default boolean isOlderThan(Timestamp other) { + return this.compareTo(checkNotNull(other)) < 0; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/ClusterCommunicationService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/ClusterCommunicationService.java new file mode 100644 index 00000000..161a8528 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/ClusterCommunicationService.java @@ -0,0 +1,166 @@ +/* + * Copyright 2014-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.cluster.messaging; + +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.onosproject.cluster.NodeId; + +/** + * Service for assisting communications between controller cluster nodes. + */ +public interface ClusterCommunicationService { + + /** + * Adds a new subscriber for the specified message subject. + * + * @param subject message subject + * @param subscriber message subscriber + * @param executor executor to use for running handler. + * @deprecated in Cardinal Release + */ + @Deprecated + void addSubscriber(MessageSubject subject, ClusterMessageHandler subscriber, ExecutorService executor); + + /** + * Broadcasts a message to all controller nodes. + * + * @param message message to send + * @param subject message subject + * @param encoder function for encoding message to byte[] + * @param message type + */ + void broadcast(M message, + MessageSubject subject, + Function encoder); + + /** + * Broadcasts a message to all controller nodes including self. + * + * @param message message to send + * @param subject message subject + * @param encoder function for encoding message to byte[] + * @param message type + */ + void broadcastIncludeSelf(M message, + MessageSubject subject, + Function encoder); + + /** + * Sends a message to the specified controller node. + * + * @param message message to send + * @param subject message subject + * @param encoder function for encoding message to byte[] + * @param toNodeId destination node identifier + * @param message type + * @return future that is completed when the message is sent + */ + CompletableFuture unicast(M message, + MessageSubject subject, + Function encoder, + NodeId toNodeId); + + /** + * Multicasts a message to a set of controller nodes. + * + * @param message message to send + * @param subject message subject + * @param encoder function for encoding message to byte[] + * @param nodeIds recipient node identifiers + * @param message type + */ + void multicast(M message, + MessageSubject subject, + Function encoder, + Set nodeIds); + + /** + * Sends a message and expects a reply. + * + * @param message message to send + * @param subject message subject + * @param encoder function for encoding request to byte[] + * @param decoder function for decoding response from byte[] + * @param toNodeId recipient node identifier + * @param request type + * @param reply type + * @return reply future + */ + CompletableFuture sendAndReceive(M message, + MessageSubject subject, + Function encoder, + Function decoder, + NodeId toNodeId); + + /** + * Adds a new subscriber for the specified message subject. + * + * @param subject message subject + * @param decoder decoder for resurrecting incoming message + * @param handler handler function that processes the incoming message and produces a reply + * @param encoder encoder for serializing reply + * @param executor executor to run this handler on + * @param incoming message type + * @param reply message type + */ + void addSubscriber(MessageSubject subject, + Function decoder, + Function handler, + Function encoder, + Executor executor); + + /** + * Adds a new subscriber for the specified message subject. + * + * @param subject message subject + * @param decoder decoder for resurrecting incoming message + * @param handler handler function that processes the incoming message and produces a reply + * @param encoder encoder for serializing reply + * @param incoming message type + * @param reply message type + */ + void addSubscriber(MessageSubject subject, + Function decoder, + Function> handler, + Function encoder); + + /** + * Adds a new subscriber for the specified message subject. + * + * @param subject message subject + * @param decoder decoder to resurrecting incoming message + * @param handler handler for handling message + * @param executor executor to run this handler on + * @param incoming message type + */ + void addSubscriber(MessageSubject subject, + Function decoder, + Consumer handler, + Executor executor); + + /** + * Removes a subscriber for the specified message subject. + * + * @param subject message subject + */ + void removeSubscriber(MessageSubject subject); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/ClusterMessage.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/ClusterMessage.java new file mode 100644 index 00000000..46560e4c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/ClusterMessage.java @@ -0,0 +1,160 @@ +/* + * Copyright 2014-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.cluster.messaging; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Objects; + +import org.onlab.util.ByteArraySizeHashPrinter; +import org.onosproject.cluster.NodeId; + +import com.google.common.base.Charsets; +import com.google.common.base.MoreObjects; + +// TODO: Should payload type be ByteBuffer? +/** + * Base message for cluster-wide communications. + */ +public class ClusterMessage { + + private final NodeId sender; + private final MessageSubject subject; + private final byte[] payload; + private transient byte[] response; + + /** + * Creates a cluster message. + * + * @param sender message sender + * @param subject message subject + * @param payload message payload + */ + public ClusterMessage(NodeId sender, MessageSubject subject, byte[] payload) { + this.sender = sender; + this.subject = subject; + this.payload = payload; + } + + /** + * Returns the id of the controller sending this message. + * + * @return message sender id. + */ + public NodeId sender() { + return sender; + } + + /** + * Returns the message subject indicator. + * + * @return message subject + */ + public MessageSubject subject() { + return subject; + } + + /** + * Returns the message payload. + * + * @return message payload. + */ + public byte[] payload() { + return payload; + } + + /** + * Records the response to be sent to the sender. + * + * @param data response payload + */ + public void respond(byte[] data) { + response = data; + } + + /** + * Returns the response to be sent to the sender. + * + * @return response bytes + */ + public byte[] response() { + return response; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("sender", sender) + .add("subject", subject) + .add("payload", ByteArraySizeHashPrinter.of(payload)) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof ClusterMessage)) { + return false; + } + + ClusterMessage that = (ClusterMessage) o; + + return Objects.equals(this.sender, that.sender) && + Objects.equals(this.subject, that.subject) && + Arrays.equals(this.payload, that.payload); + } + + /** + * Serializes this instance. + * @return bytes + */ + public byte[] getBytes() { + byte[] senderBytes = sender.toString().getBytes(Charsets.UTF_8); + byte[] subjectBytes = subject.value().getBytes(Charsets.UTF_8); + int capacity = 12 + senderBytes.length + subjectBytes.length + payload.length; + ByteBuffer buffer = ByteBuffer.allocate(capacity); + buffer.putInt(senderBytes.length); + buffer.put(senderBytes); + buffer.putInt(subjectBytes.length); + buffer.put(subjectBytes); + buffer.putInt(payload.length); + buffer.put(payload); + return buffer.array(); + } + + /** + * Decodes a new ClusterMessage from raw bytes. + * @param bytes raw bytes + * @return cluster message + */ + public static ClusterMessage fromBytes(byte[] bytes) { + ByteBuffer buffer = ByteBuffer.wrap(bytes); + byte[] senderBytes = new byte[buffer.getInt()]; + buffer.get(senderBytes); + byte[] subjectBytes = new byte[buffer.getInt()]; + buffer.get(subjectBytes); + byte[] payloadBytes = new byte[buffer.getInt()]; + buffer.get(payloadBytes); + + return new ClusterMessage(new NodeId(new String(senderBytes, Charsets.UTF_8)), + new MessageSubject(new String(subjectBytes, Charsets.UTF_8)), + payloadBytes); + } + + @Override + public int hashCode() { + return Objects.hash(sender, subject, payload); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/ClusterMessageHandler.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/ClusterMessageHandler.java new file mode 100644 index 00000000..ce770a81 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/ClusterMessageHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2014 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.cluster.messaging; + +/** + * Interface for handling cluster messages. + */ +public interface ClusterMessageHandler { + + /** + * Handles/Processes the cluster message. + * @param message cluster message. + */ + void handle(ClusterMessage message); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/Endpoint.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/Endpoint.java new file mode 100644 index 00000000..2ac50dfd --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/Endpoint.java @@ -0,0 +1,75 @@ +/* + * Copyright 2014-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.cluster.messaging; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Objects; + +import org.onlab.packet.IpAddress; + +import com.google.common.base.MoreObjects; + +/** + * Representation of a TCP/UDP communication end point. + */ +public final class Endpoint { + + private final int port; + private final IpAddress ip; + + public Endpoint(IpAddress host, int port) { + this.ip = checkNotNull(host); + this.port = port; + } + + public IpAddress host() { + return ip; + } + + public int port() { + return port; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("ip", ip) + .add("port", port) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(ip, port); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Endpoint that = (Endpoint) obj; + return Objects.equals(this.port, that.port) && + Objects.equals(this.ip, that.ip); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/MessageSubject.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/MessageSubject.java new file mode 100644 index 00000000..8d5e313d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/MessageSubject.java @@ -0,0 +1,68 @@ +/* + * Copyright 2014 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.cluster.messaging; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Objects; + +/** + * Representation of a message subject. + * Cluster messages have associated subjects that dictate how they get handled + * on the receiving side. + */ +public final class MessageSubject { + + private final String value; + + public MessageSubject(String value) { + this.value = checkNotNull(value); + } + + public String value() { + return value; + } + + @Override + public String toString() { + return value; + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + MessageSubject that = (MessageSubject) obj; + return Objects.equals(this.value, that.value); + } + + // for serializer + protected MessageSubject() { + this.value = ""; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/MessagingService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/MessagingService.java new file mode 100644 index 00000000..6ccd4835 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/MessagingService.java @@ -0,0 +1,75 @@ +/* + * Copyright 2014-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.cluster.messaging; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * Interface for low level messaging primitives. + */ +public interface MessagingService { + + /** + * Sends a message asynchronously to the specified communication end point. + * The message is specified using the type and payload. + * @param ep end point to send the message to. + * @param type type of message. + * @param payload message payload bytes. + * @return future that is completed when the message is sent + */ + CompletableFuture sendAsync(Endpoint ep, String type, byte[] payload); + + /** + * Sends a message synchronously and waits for a response. + * @param ep end point to send the message to. + * @param type type of message. + * @param payload message payload. + * @return a response future + */ + CompletableFuture sendAndReceive(Endpoint ep, String type, byte[] payload); + + /** + * Registers a new message handler for message type. + * @param type message type. + * @param handler message handler + * @param executor executor to use for running message handler logic. + */ + void registerHandler(String type, Consumer handler, Executor executor); + + /** + * Registers a new message handler for message type. + * @param type message type. + * @param handler message handler + * @param executor executor to use for running message handler logic. + */ + void registerHandler(String type, Function handler, Executor executor); + + /** + * Registers a new message handler for message type. + * @param type message type. + * @param handler message handler + */ + void registerHandler(String type, Function> handler); + + /** + * Unregister current handler, if one exists for message type. + * @param type message type + */ + void unregisterHandler(String type); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/package-info.java new file mode 100644 index 00000000..582c50ed --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/cluster/messaging/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Cluster messaging APIs for the use by the various distributed stores. + */ +package org.onosproject.store.cluster.messaging; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/package-info.java new file mode 100644 index 00000000..b6269ea5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Abstractions for creating and interacting with distributed stores. + */ +package org.onosproject.store; 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 new file mode 100644 index 00000000..a879cc59 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncAtomicCounter.java @@ -0,0 +1,61 @@ +/* + * 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; + +/** + * An async atomic counter dispenses monotonically increasing values. + */ +public interface AsyncAtomicCounter { + + /** + * Atomically increment by one the current value. + * + * @return updated value + */ + CompletableFuture incrementAndGet(); + + /** + * Atomically increment by one the current value. + * + * @return previous value + */ + CompletableFuture getAndIncrement(); + + /** + * Atomically adds the given value to the current value. + * + * @param delta the value to add + * @return previous value + */ + CompletableFuture getAndAdd(long delta); + + /** + * Atomically adds the given value to the current value. + * + * @param delta the value to add + * @return updated value + */ + CompletableFuture addAndGet(long delta); + + /** + * Returns the current value of the counter without modifying it. + * + * @return current value + */ + CompletableFuture get(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncConsistentMap.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncConsistentMap.java new file mode 100644 index 00000000..fee8cfa6 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AsyncConsistentMap.java @@ -0,0 +1,283 @@ +/* + * 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.Collection; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * A distributed, strongly consistent map whose methods are all executed asynchronously. + *

+ * This map offers strong read-after-update (where update == create/update/delete) + * consistency. All operations to the map are serialized and applied in a consistent + * manner. + *

+ * The stronger consistency comes at the expense of availability in + * the event of a network partition. A network partition can be either due to + * a temporary disruption in network connectivity between participating nodes + * or due to a node being temporarily down. + *

+ * All values stored in this map are versioned and the API supports optimistic + * concurrency by allowing conditional updates that take into consideration + * the version or value that was previously read. + *

+ * This map does not allow null values. All methods can throw a ConsistentMapException + * (which extends RuntimeException) to indicate failures. + * + */ +public interface AsyncConsistentMap { + + /** + * Returns the number of entries in the map. + * + * @return a future for map size. + */ + CompletableFuture size(); + + /** + * Returns true if the map is empty. + * + * @return a future whose value will be true if map has no entries, false otherwise. + */ + CompletableFuture isEmpty(); + + /** + * Returns true if this map contains a mapping for the specified key. + * + * @param key key + * @return a future whose value will be true if map contains key, false otherwise. + */ + CompletableFuture containsKey(K key); + + /** + * Returns true if this map contains the specified value. + * + * @param value value + * @return a future whose value will be true if map contains value, false otherwise. + */ + CompletableFuture containsValue(V value); + + /** + * Returns the value (and version) to which the specified key is mapped, or null if this + * map contains no mapping for the key. + * + * @param key the key whose associated value (and version) is to be returned + * @return a future value (and version) to which the specified key is mapped, or null if + * this map contains no mapping for the key + */ + CompletableFuture> get(K key); + + /** + * If the specified key is not already associated with a value (or is mapped to null), + * attempts to compute its value using the given mapping function and enters it into + * this map unless null. + * If a conflicting concurrent modification attempt is detected, the returned future + * will be completed exceptionally with ConsistentMapException.ConcurrentModification. + * @param key key with which the specified value is to be associated + * @param mappingFunction the function to compute a value + * @return the current (existing or computed) value associated with the specified key, + * or null if the computed value is null + */ + CompletableFuture> computeIfAbsent(K key, + Function mappingFunction); + + /** + * If the value for the specified key is present and non-null, attempts to compute a new + * mapping given the key and its current mapped value. + * If the computed value is null, the current mapping will be removed from the map. + * If a conflicting concurrent modification attempt is detected, the returned future + * will be completed exceptionally with ConsistentMapException.ConcurrentModification. + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if computed value is null + */ + CompletableFuture> computeIfPresent(K key, + BiFunction remappingFunction); + + /** + * Attempts to compute a mapping for the specified key and its current mapped value (or + * null if there is no current mapping). + * If the computed value is null, the current mapping (if one exists) will be removed from the map. + * If a conflicting concurrent modification attempt is detected, the returned future + * will be completed exceptionally with ConsistentMapException.ConcurrentModification. + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if computed value is null + */ + CompletableFuture> compute(K key, + BiFunction remappingFunction); + + /** + * If the value for the specified key satisfies a condition, attempts to compute a new + * mapping given the key and its current mapped value. + * If the computed value is null, the current mapping will be removed from the map. + * If a conflicting concurrent modification attempt is detected, the returned future + * will be completed exceptionally with ConsistentMapException.ConcurrentModification. + * @param key key with which the specified value is to be associated + * @param condition condition that should evaluate to true for the computation to proceed + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or the old value if condition evaluates to false + */ + CompletableFuture> computeIf(K key, + Predicate condition, + BiFunction remappingFunction); + + /** + * Associates the specified value with the specified key in this map (optional operation). + * If the map previously contained a mapping for the key, the old value is replaced by the + * specified value. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value (and version) associated with key, or null if there was + * no mapping for key. + */ + CompletableFuture> put(K key, V value); + + /** + * Associates the specified value with the specified key in this map (optional operation). + * If the map previously contained a mapping for the key, the old value is replaced by the + * specified value. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return new value. + */ + CompletableFuture> putAndGet(K key, V value); + + /** + * Removes the mapping for a key from this map if it is present (optional operation). + * + * @param key key whose value is to be removed from the map + * @return the value (and version) to which this map previously associated the key, + * or null if the map contained no mapping for the key. + */ + CompletableFuture> remove(K key); + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + * @return future that will be successfully completed when the map is cleared + */ + CompletableFuture clear(); + + /** + * Returns a Set view of the keys contained in this map. + * This method differs from the behavior of java.util.Map.keySet() in that + * what is returned is a unmodifiable snapshot view of the keys in the ConsistentMap. + * Attempts to modify the returned set, whether direct or via its iterator, + * result in an UnsupportedOperationException. + * + * @return a set of the keys contained in this map + */ + CompletableFuture> keySet(); + + /** + * Returns the collection of values (and associated versions) contained in this map. + * This method differs from the behavior of java.util.Map.values() in that + * what is returned is a unmodifiable snapshot view of the values in the ConsistentMap. + * Attempts to modify the returned collection, whether direct or via its iterator, + * result in an UnsupportedOperationException. + * + * @return a collection of the values (and associated versions) contained in this map + */ + CompletableFuture>> values(); + + /** + * Returns the set of entries contained in this map. + * This method differs from the behavior of java.util.Map.entrySet() in that + * what is returned is a unmodifiable snapshot view of the entries in the ConsistentMap. + * Attempts to modify the returned set, whether direct or via its iterator, + * result in an UnsupportedOperationException. + * + * @return set of entries contained in this map. + */ + CompletableFuture>>> entrySet(); + + /** + * If the specified key is not already associated with a value + * associates it with the given value and returns null, else returns the current value. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with the specified key or null + * if key does not already mapped to a value. + */ + CompletableFuture> putIfAbsent(K key, V value); + + /** + * Removes the entry for the specified key only if it is currently + * mapped to the specified value. + * + * @param key key with which the specified value is associated + * @param value value expected to be associated with the specified key + * @return true if the value was removed + */ + CompletableFuture remove(K key, V value); + + /** + * Removes the entry for the specified key only if its current + * version in the map is equal to the specified version. + * + * @param key key with which the specified version is associated + * @param version version expected to be associated with the specified key + * @return true if the value was removed + */ + CompletableFuture remove(K key, long version); + + /** + * Replaces the entry for the specified key only if currently mapped + * to the specified value. + * + * @param key key with which the specified value is associated + * @param oldValue value expected to be associated with the specified key + * @param newValue value to be associated with the specified key + * @return true if the value was replaced + */ + CompletableFuture replace(K key, V oldValue, V newValue); + + /** + * Replaces the entry for the specified key only if it is currently mapped to the + * specified version. + * + * @param key key key with which the specified value is associated + * @param oldVersion version expected to be associated with the specified key + * @param newValue value to be associated with the specified key + * @return true if the value was replaced + */ + CompletableFuture replace(K key, long oldVersion, V newValue); + + /** + * Registers the specified listener to be notified whenever the map is updated. + * + * @param listener listener to notify about map events + */ + void addListener(MapEventListener listener); + + /** + * Unregisters the specified listener such that it will no longer + * receive map change notifications. + * + * @param listener listener to unregister + */ + void removeListener(MapEventListener listener); +} 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 new file mode 100644 index 00000000..f620e082 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounter.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.store.service; + +/** + * Distributed version of java.util.concurrent.atomic.AtomicLong. + */ +public interface AtomicCounter { + + /** + * Atomically increment by one the current value. + * + * @return updated value + */ + long incrementAndGet(); + + /** + * Atomically increment by one the current value. + * + * @return previous value + */ + long getAndIncrement(); + + /** + * Atomically adds the given value to the current value. + * + * @param delta the value to add + * @return previous value + */ + long getAndAdd(long delta); + + /** + * Atomically adds the given value to the current value. + * + * @param delta the value to add + * @return updated value + */ + long addAndGet(long delta); + + /** + * Returns the current value of the counter without modifying it. + * + * @return current value + */ + long get(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounterBuilder.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounterBuilder.java new file mode 100644 index 00000000..41a19f0d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicCounterBuilder.java @@ -0,0 +1,75 @@ +/* + * 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; + +/** + * Builder for AtomicCounter. + */ +public interface AtomicCounterBuilder { + + /** + * Sets the name for the atomic counter. + *

+ * Each atomic counter is identified by a unique name. + *

+ *

+ * Note: This is a mandatory parameter. + *

+ * + * @param name name of the atomic counter + * @return this AtomicCounterBuilder + */ + AtomicCounterBuilder withName(String name); + + /** + * Creates this counter on the partition that spans the entire cluster. + *

+ * When partitioning is disabled, the counter state will be + * ephemeral and does not survive a full cluster restart. + *

+ *

+ * Note: By default partitions are enabled. + *

+ * @return this AtomicCounterBuilder + */ + AtomicCounterBuilder withPartitionsDisabled(); + + /** + * Instantiates Metering service to gather usage and performance metrics. + * By default, usage data will be stored. + * + * @return this AtomicCounterBuilder + */ + AtomicCounterBuilder withMeteringDisabled(); + + /** + * Builds a AtomicCounter based on the configuration options + * supplied to this builder. + * + * @return new AtomicCounter + * @throws java.lang.RuntimeException if a mandatory parameter is missing + */ + AtomicCounter build(); + + /** + * Builds a AsyncAtomicCounter based on the configuration options + * supplied to this builder. + * + * @return new AsyncAtomicCounter + * @throws java.lang.RuntimeException if a mandatory parameter is missing + */ + AsyncAtomicCounter buildAsyncCounter(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValue.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValue.java new file mode 100644 index 00000000..dfa0fb3c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValue.java @@ -0,0 +1,69 @@ +/* + * 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; + +/** + * Distributed version of java.util.concurrent.atomic.AtomicReference. + * + * @param value type + */ +public interface AtomicValue { + + /** + * Atomically sets the value to the given updated value if the current value is equal to the expected value. + *

+ * IMPORTANT: Equality is based on the equality of the serialized byte[] representations. + *

+ * @param expect the expected value + * @param update the new value + * @return true if successful. false return indicates that the actual value was not equal to the expected value. + */ + boolean compareAndSet(V expect, V update); + + /** + * Gets the current value. + * @return current value + */ + V get(); + + /** + * Atomically sets to the given value and returns the old value. + * @param value the new value + * @return previous value + */ + V getAndSet(V value); + + /** + * Sets to the given value. + * @param value new value + */ + void set(V value); + + /** + * Registers the specified listener to be notified whenever the atomic value is updated. + * + * @param listener listener to notify about events + */ + void addListener(AtomicValueEventListener listener); + + /** + * Unregisters the specified listener such that it will no longer + * receive atomic value update notifications. + * + * @param listener listener to unregister + */ + void removeListener(AtomicValueEventListener listener); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValueBuilder.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValueBuilder.java new file mode 100644 index 00000000..3478ce00 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValueBuilder.java @@ -0,0 +1,78 @@ +/* + * 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; + +/** + * Builder for constructing new AtomicValue instances. + * + * @param atomic value type + */ +public interface AtomicValueBuilder { + /** + * Sets the name for the atomic value. + *

+ * Each atomic value is identified by a unique name. + *

+ *

+ * Note: This is a mandatory parameter. + *

+ * + * @param name name of the atomic value + * @return this AtomicValueBuilder for method chaining + */ + AtomicValueBuilder withName(String name); + + /** + * Sets a serializer that can be used to serialize the value. + *

+ * Note: This is a mandatory parameter. + *

+ * + * @param serializer serializer + * @return this AtomicValueBuilder for method chaining + */ + AtomicValueBuilder withSerializer(Serializer serializer); + + /** + * Creates this atomic value on the partition that spans the entire cluster. + *

+ * When partitioning is disabled, the value state will be + * ephemeral and does not survive a full cluster restart. + *

+ *

+ * Note: By default partitions are enabled. + *

+ * @return this AtomicValueBuilder for method chaining + */ + AtomicValueBuilder withPartitionsDisabled(); + + /** + * Instantiates Metering service to gather usage and performance metrics. + * By default, usage data will be stored. + * + * @return this AtomicValueBuilder for method chaining + */ + AtomicValueBuilder withMeteringDisabled(); + + /** + * Builds a AtomicValue based on the configuration options + * supplied to this builder. + * + * @return new AtomicValue + * @throws java.lang.RuntimeException if a mandatory parameter is missing + */ + AtomicValue build(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValueEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValueEvent.java new file mode 100644 index 00000000..1bce1365 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValueEvent.java @@ -0,0 +1,109 @@ +/* + * 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.Objects; + +import com.google.common.base.MoreObjects; + +/** + * Representation of a AtomicValue update notification. + * + * @param atomic value type + */ +public final class AtomicValueEvent { + + /** + * AtomicValueEvent type. + */ + public enum Type { + + /** + * Value was updated. + */ + UPDATE, + } + + private final String name; + private final Type type; + private final V value; + + /** + * Creates a new event object. + * + * @param name AtomicValue name + * @param type the type of the event + * @param value the new value + */ + public AtomicValueEvent(String name, Type type, V value) { + this.name = name; + this.type = type; + this.value = value; + } + + /** + * Returns the AtomicValue name. + * + * @return name of atomic value + */ + public String name() { + return name; + } + + /** + * Returns the type of the event. + * + * @return the type of the event + */ + public Type type() { + return type; + } + + /** + * Returns the new updated value. + * + * @return the value + */ + public V value() { + return value; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof AtomicValueEvent)) { + return false; + } + + AtomicValueEvent that = (AtomicValueEvent) o; + return Objects.equals(this.name, that.name) && + Objects.equals(this.type, that.type) && + Objects.equals(this.value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(name, type, value); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("name", name) + .add("type", type) + .add("value", value) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValueEventListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValueEventListener.java new file mode 100644 index 00000000..b29d903b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/AtomicValueEventListener.java @@ -0,0 +1,28 @@ +/* + * 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; + +/** + * Listener to be notified about updates to a AtomicValue. + */ +public interface AtomicValueEventListener { + /** + * Reacts to the specified event. + * + * @param event the event + */ + void event(AtomicValueEvent event); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/ConsistentMap.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/ConsistentMap.java new file mode 100644 index 00000000..289da202 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/ConsistentMap.java @@ -0,0 +1,291 @@ +/* + * 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.Collection; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * A distributed, strongly consistent key-value map. + *

+ * This map offers strong read-after-update (where update == create/update/delete) + * consistency. All operations to the map are serialized and applied in a consistent + * manner. + *

+ * The stronger consistency comes at the expense of availability in + * the event of a network partition. A network partition can be either due to + * a temporary disruption in network connectivity between participating nodes + * or due to a node being temporarily down. + *

+ * All values stored in this map are versioned and the API supports optimistic + * concurrency by allowing conditional updates that take into consideration + * the version or value that was previously read. + *

+ * This map does not allow null values. All methods can throw a ConsistentMapException + * (which extends RuntimeException) to indicate failures. + * + */ +public interface ConsistentMap { + + /** + * Returns the number of entries in the map. + * + * @return map size. + */ + int size(); + + /** + * Returns true if the map is empty. + * + * @return true if map has no entries, false otherwise + */ + boolean isEmpty(); + + /** + * Returns true if this map contains a mapping for the specified key. + * + * @param key key + * @return true if map contains key, false otherwise + */ + boolean containsKey(K key); + + /** + * Returns true if this map contains the specified value. + * + * @param value value + * @return true if map contains value, false otherwise. + */ + boolean containsValue(V value); + + /** + * Returns the value (and version) to which the specified key is mapped, or null if this + * map contains no mapping for the key. + * + * @param key the key whose associated value (and version) is to be returned + * @return the value (and version) to which the specified key is mapped, or null if + * this map contains no mapping for the key + */ + Versioned get(K key); + + /** + * If the specified key is not already associated with a value (or is mapped to null), + * attempts to compute its value using the given mapping function and enters it into + * this map unless null. + * + * @param key key with which the specified value is to be associated + * @param mappingFunction the function to compute a value + * @return the current (existing or computed) value associated with the specified key, + * or null if the computed value is null. Method throws {@code ConsistentMapException.ConcurrentModification} + * if a concurrent modification of map is detected + */ + Versioned computeIfAbsent(K key, + Function mappingFunction); + + /** + * Attempts to compute a mapping for the specified key and its current mapped value (or + * null if there is no current mapping). + * If the computed value is null, the current mapping will be removed from the map. + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none. + * This method throws {@code ConsistentMapException.ConcurrentModification} + * if a concurrent modification of map is detected + */ + Versioned compute(K key, + BiFunction remappingFunction); + + /** + * If the value for the specified key is present and non-null, attempts to compute a new + * mapping given the key and its current mapped value. + * If the computed value is null, the current mapping will be removed from the map. + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or null if none. + * This method throws {@code ConsistentMapException.ConcurrentModification} + * if a concurrent modification of map is detected + */ + Versioned computeIfPresent(K key, + BiFunction remappingFunction); + + /** + * If the value for the specified key satisfies a condition, attempts to compute a new + * mapping given the key and its current mapped value. + * If the computed value is null, the current mapping will be removed from the map. + * + * @param key key with which the specified value is to be associated + * @param condition condition that should evaluate to true for the computation to proceed + * @param remappingFunction the function to compute a value + * @return the new value associated with the specified key, or the old value if condition evaluates to false. + * This method throws {@code ConsistentMapException.ConcurrentModification} if a concurrent + * modification of map is detected + */ + Versioned computeIf(K key, + Predicate condition, + BiFunction remappingFunction); + + /** + * Associates the specified value with the specified key in this map (optional operation). + * If the map previously contained a mapping for the key, the old value is replaced by the + * specified value. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value (and version) associated with key, or null if there was + * no mapping for key. + */ + Versioned put(K key, V value); + + /** + * Associates the specified value with the specified key in this map (optional operation). + * If the map previously contained a mapping for the key, the old value is replaced by the + * specified value. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return new value. + */ + Versioned putAndGet(K key, V value); + + /** + * Removes the mapping for a key from this map if it is present (optional operation). + * + * @param key key whose value is to be removed from the map + * @return the value (and version) to which this map previously associated the key, + * or null if the map contained no mapping for the key. + */ + Versioned remove(K key); + + /** + * Removes all of the mappings from this map (optional operation). + * The map will be empty after this call returns. + */ + void clear(); + + /** + * Returns a Set view of the keys contained in this map. + * This method differs from the behavior of java.util.Map.keySet() in that + * what is returned is a unmodifiable snapshot view of the keys in the ConsistentMap. + * Attempts to modify the returned set, whether direct or via its iterator, + * result in an UnsupportedOperationException. + * + * @return a set of the keys contained in this map + */ + Set keySet(); + + /** + * Returns the collection of values (and associated versions) contained in this map. + * This method differs from the behavior of java.util.Map.values() in that + * what is returned is a unmodifiable snapshot view of the values in the ConsistentMap. + * Attempts to modify the returned collection, whether direct or via its iterator, + * result in an UnsupportedOperationException. + * + * @return a collection of the values (and associated versions) contained in this map + */ + Collection> values(); + + /** + * Returns the set of entries contained in this map. + * This method differs from the behavior of java.util.Map.entrySet() in that + * what is returned is a unmodifiable snapshot view of the entries in the ConsistentMap. + * Attempts to modify the returned set, whether direct or via its iterator, + * result in an UnsupportedOperationException. + * + * @return set of entries contained in this map. + */ + Set>> entrySet(); + + /** + * If the specified key is not already associated with a value + * associates it with the given value and returns null, else returns the current value. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with the specified key or null + * if key does not already mapped to a value. + */ + Versioned putIfAbsent(K key, V value); + + /** + * Removes the entry for the specified key only if it is currently + * mapped to the specified value. + * + * @param key key with which the specified value is associated + * @param value value expected to be associated with the specified key + * @return true if the value was removed + */ + boolean remove(K key, V value); + + /** + * Removes the entry for the specified key only if its current + * version in the map is equal to the specified version. + * + * @param key key with which the specified version is associated + * @param version version expected to be associated with the specified key + * @return true if the value was removed + */ + boolean remove(K key, long version); + + /** + * Replaces the entry for the specified key only if currently mapped + * to the specified value. + * + * @param key key with which the specified value is associated + * @param oldValue value expected to be associated with the specified key + * @param newValue value to be associated with the specified key + * @return true if the value was replaced + */ + boolean replace(K key, V oldValue, V newValue); + + /** + * Replaces the entry for the specified key only if it is currently mapped to the + * specified version. + * + * @param key key key with which the specified value is associated + * @param oldVersion version expected to be associated with the specified key + * @param newValue value to be associated with the specified key + * @return true if the value was replaced + */ + boolean replace(K key, long oldVersion, V newValue); + + /** + * Registers the specified listener to be notified whenever the map is updated. + * + * @param listener listener to notify about map events + */ + void addListener(MapEventListener listener); + + /** + * Unregisters the specified listener such that it will no longer + * receive map change notifications. + * + * @param listener listener to unregister + */ + void removeListener(MapEventListener listener); + + /** + * Returns a java.util.Map instance backed by this ConsistentMap. + * @return java.util.Map + */ + Map asJavaMap(); +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/ConsistentMapBuilder.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/ConsistentMapBuilder.java new file mode 100644 index 00000000..847adaf6 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/ConsistentMapBuilder.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.store.service; + +import org.onosproject.core.ApplicationId; + +/** + * Builder for consistent maps. + * + * @param type for map key + * @param type for map value + */ +public interface ConsistentMapBuilder { + + /** + * Sets the name of the map. + *

+ * Each consistent map is identified by a unique map name. + *

+ *

+ * Note: This is a mandatory parameter. + *

+ * + * @param name name of the consistent map + * @return this ConsistentMapBuilder + */ + ConsistentMapBuilder withName(String name); + + /** + * Sets the owner applicationId for the map. + *

+ * Note: If {@code purgeOnUninstall} option is enabled, applicationId + * must be specified. + *

+ * + * @param id applicationId owning the consistent map + * @return this ConsistentMapBuilder + */ + ConsistentMapBuilder withApplicationId(ApplicationId id); + + /** + * Sets a serializer that can be used to serialize + * both the keys and values inserted into the map. The serializer + * builder should be pre-populated with any classes that will be + * put into the map. + *

+ * Note: This is a mandatory parameter. + *

+ * + * @param serializer serializer + * @return this ConsistentMapBuilder + */ + ConsistentMapBuilder withSerializer(Serializer serializer); + + /** + * Disables distribution of map entries across multiple database partitions. + *

+ * When partitioning is disabled, the returned map will have a single partition + * that spans the entire cluster. Furthermore, the changes made to the map are + * ephemeral and do not survive a full cluster restart. + *

+ *

+ * Disabling partitions is more appropriate when the returned map is used for + * coordination activities such as leader election and not for long term data persistence. + *

+ *

+ * Note: By default partitions are enabled and entries in the map are durable. + *

+ * @return this ConsistentMapBuilder + */ + ConsistentMapBuilder withPartitionsDisabled(); + + /** + * Disables map updates. + *

+ * Attempt to update the built map will throw {@code UnsupportedOperationException}. + * + * @return this ConsistentMapBuilder + */ + ConsistentMapBuilder withUpdatesDisabled(); + + /** + * Purges map contents when the application owning the map is uninstalled. + *

+ * When this option is enabled, the caller must provide a applicationId via + * the {@code withAppliationId} builder method. + *

+ * By default map entries will NOT be purged when owning application is uninstalled. + * + * @return this ConsistentMapBuilder + */ + ConsistentMapBuilder withPurgeOnUninstall(); + + /** + * Instantiates Metering service to gather usage and performance metrics. + * By default, usage data will be stored. + * + * @return this ConsistentMapBuilder + */ + ConsistentMapBuilder withMeteringDisabled(); + + /** + * Provides weak consistency for map gets. + *

+ * While this can lead to improved read performance, it can also make the behavior + * heard to reason. Only turn this on if you know what you are doing. By default + * reads are strongly consistent. + * + * @return this ConsistentMapBuilder + */ + ConsistentMapBuilder withRelaxedReadConsistency(); + + /** + * Builds an consistent map based on the configuration options + * supplied to this builder. + * + * @return new consistent map + * @throws java.lang.RuntimeException if a mandatory parameter is missing + */ + ConsistentMap build(); + + /** + * Builds an async consistent map based on the configuration options + * supplied to this builder. + * + * @return new async consistent map + * @throws java.lang.RuntimeException if a mandatory parameter is missing + */ + AsyncConsistentMap buildAsyncMap(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/ConsistentMapException.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/ConsistentMapException.java new file mode 100644 index 00000000..94ed649f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/ConsistentMapException.java @@ -0,0 +1,48 @@ +/* + * 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; + +/** + * Top level exception for ConsistentMap failures. + */ +@SuppressWarnings("serial") +public class ConsistentMapException extends StorageException { + public ConsistentMapException() { + } + + public ConsistentMapException(Throwable t) { + super(t); + } + + /** + * ConsistentMap operation timeout. + */ + public static class Timeout extends ConsistentMapException { + } + + /** + * ConsistentMap update conflicts with an in flight transaction. + */ + public static class ConcurrentModification extends ConsistentMapException { + } + + /** + * ConsistentMap operation interrupted. + */ + public static class Interrupted extends ConsistentMapException { + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DatabaseUpdate.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DatabaseUpdate.java new file mode 100644 index 00000000..8cac5968 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DatabaseUpdate.java @@ -0,0 +1,220 @@ +/* + * 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 static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.base.MoreObjects; + +/** + * Database update operation. + * + */ +public final class DatabaseUpdate { + + /** + * Type of database update operation. + */ + public static enum Type { + /** + * Insert/Update entry without any checks. + */ + PUT, + /** + * Insert an entry iff there is no existing entry for that key. + */ + PUT_IF_ABSENT, + + /** + * Update entry if the current version matches specified version. + */ + PUT_IF_VERSION_MATCH, + + /** + * Update entry if the current value matches specified value. + */ + PUT_IF_VALUE_MATCH, + + /** + * Remove entry without any checks. + */ + REMOVE, + + /** + * Remove entry if the current version matches specified version. + */ + REMOVE_IF_VERSION_MATCH, + + /** + * Remove entry if the current value matches specified value. + */ + REMOVE_IF_VALUE_MATCH, + } + + private Type type; + private String mapName; + private String key; + private byte[] value; + private byte[] currentValue; + private long currentVersion = -1; + + /** + * Returns the type of update operation. + * @return type of update. + */ + public Type type() { + return type; + } + + /** + * Returns the name of map being updated. + * @return map name. + */ + public String mapName() { + return mapName; + } + + /** + * Returns the item key being updated. + * @return item key + */ + public String key() { + return key; + } + + /** + * Returns the new value. + * @return item's target value. + */ + public byte[] value() { + return value; + } + + /** + * Returns the expected current value in the database value for the key. + * @return current value in database. + */ + public byte[] currentValue() { + return currentValue; + } + + /** + * Returns the expected current version in the database for the key. + * @return expected version. + */ + public long currentVersion() { + return currentVersion; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("type", type) + .add("mapName", mapName) + .add("key", key) + .add("value", value) + .add("currentValue", currentValue) + .add("currentVersion", currentVersion) + .toString(); + } + + /** + * Creates a new builder instance. + * + * @return builder. + */ + public static Builder newBuilder() { + return new Builder(); + } + + /** + * DatabaseUpdate builder. + * + */ + public static final class Builder { + + private DatabaseUpdate update = new DatabaseUpdate(); + + public DatabaseUpdate build() { + validateInputs(); + return update; + } + + public Builder withType(Type type) { + update.type = checkNotNull(type, "type cannot be null"); + return this; + } + + public Builder withMapName(String mapName) { + update.mapName = checkNotNull(mapName, "mapName cannot be null"); + return this; + } + + public Builder withKey(String key) { + update.key = checkNotNull(key, "key cannot be null"); + return this; + } + + public Builder withCurrentValue(byte[] value) { + update.currentValue = checkNotNull(value, "currentValue cannot be null"); + return this; + } + + public Builder withValue(byte[] value) { + update.value = checkNotNull(value, "value cannot be null"); + return this; + } + + public Builder withCurrentVersion(long version) { + checkArgument(version >= 0, "version cannot be negative"); + update.currentVersion = version; + return this; + } + + private void validateInputs() { + checkNotNull(update.type, "type must be specified"); + checkNotNull(update.mapName, "map name must be specified"); + checkNotNull(update.key, "key must be specified"); + switch (update.type) { + case PUT: + case PUT_IF_ABSENT: + checkNotNull(update.value, "value must be specified."); + break; + case PUT_IF_VERSION_MATCH: + checkNotNull(update.value, "value must be specified."); + checkState(update.currentVersion >= 0, "current version must be specified"); + break; + case PUT_IF_VALUE_MATCH: + checkNotNull(update.value, "value must be specified."); + checkNotNull(update.currentValue, "currentValue must be specified."); + break; + case REMOVE: + break; + case REMOVE_IF_VERSION_MATCH: + checkState(update.currentVersion >= 0, "current version must be specified"); + break; + case REMOVE_IF_VALUE_MATCH: + checkNotNull(update.currentValue, "currentValue must be specified."); + break; + default: + throw new IllegalStateException("Unknown operation type"); + } + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedQueue.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedQueue.java new file mode 100644 index 00000000..cc0b00d3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedQueue.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.store.service; + +import java.util.concurrent.CompletableFuture; + +/** + * A distributed collection designed for holding elements prior to processing. + * A queue provides insertion, extraction and inspection operations. The extraction operation + * is designed to be non-blocking. + * + * @param queue entry type + */ +public interface DistributedQueue { + + /** + * Returns total number of entries in the queue. + * @return queue size + */ + long size(); + + /** + * Returns true if queue has elements in it. + * @return true is queue has elements, false otherwise + */ + default boolean isEmpty() { + return size() == 0; + } + + /** + * Inserts an entry into the queue. + * @param entry entry to insert + */ + void push(E entry); + + /** + * If the queue is non-empty, an entry will be removed from the queue and the returned future + * will be immediately completed with it. If queue is empty when this call is made, the returned + * future will be eventually completed when an entry is added to the queue. + * @return queue entry + */ + CompletableFuture pop(); + + /** + * Returns an entry from the queue without removing it. If the queue is empty returns null. + * @return queue entry or null if queue is empty + */ + E peek(); +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedQueueBuilder.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedQueueBuilder.java new file mode 100644 index 00000000..646dc28c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedQueueBuilder.java @@ -0,0 +1,79 @@ +/* + * 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; + +/** + * Builder for distributed queue. + * + * @param type queue elements. + */ +public interface DistributedQueueBuilder { + + /** + * Sets the name of the queue. + *

+ * Each queue is identified by a unique name. + *

+ *

+ * Note: This is a mandatory parameter. + *

+ * + * @param name name of the queue + * @return this DistributedQueueBuilder for method chaining + */ + DistributedQueueBuilder withName(String name); + + /** + * Sets a serializer that can be used to serialize + * the elements pushed into the queue. The serializer + * builder should be pre-populated with any classes that will be + * put into the queue. + *

+ * Note: This is a mandatory parameter. + *

+ * + * @param serializer serializer + * @return this DistributedQueueBuilder for method chaining + */ + DistributedQueueBuilder withSerializer(Serializer serializer); + + /** + * + * + * @return this DistributedQueueBuilder for method chaining + */ + DistributedQueueBuilder withMeteringDisabled(); + + + /** + * Disables persistence of queues entries. + *

+ * When persistence is disabled, a full cluster restart will wipe out all + * queue entries. + *

+ * @return this DistributedQueueBuilder for method chaining + */ + DistributedQueueBuilder withPersistenceDisabled(); + + /** + * Builds a queue based on the configuration options + * supplied to this builder. + * + * @return new distributed queue + * @throws java.lang.RuntimeException if a mandatory parameter is missing + */ + DistributedQueue build(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedSet.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedSet.java new file mode 100644 index 00000000..460206ec --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedSet.java @@ -0,0 +1,41 @@ +/* + * 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.Set; + +/** + * A distributed collection designed for holding unique elements. + * + * @param set entry type + */ +public interface DistributedSet extends Set { + + /** + * Registers the specified listener to be notified whenever + * the set is updated. + * + * @param listener listener to notify about set update events + */ + void addListener(SetEventListener listener); + + /** + * Unregisters the specified listener. + * + * @param listener listener to unregister. + */ + void removeListener(SetEventListener listener); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedSetBuilder.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedSetBuilder.java new file mode 100644 index 00000000..f5a44c93 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/DistributedSetBuilder.java @@ -0,0 +1,132 @@ +/* + * 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 org.onosproject.core.ApplicationId; + +/** + * Builder for distributed set. + * + * @param type set elements. + */ +public interface DistributedSetBuilder { + + /** + * Sets the name of the set. + *

+ * Each set is identified by a unique name. + *

+ *

+ * Note: This is a mandatory parameter. + *

+ * + * @param name name of the set + * @return this DistributedSetBuilder + */ + DistributedSetBuilder withName(String name); + + /** + * Sets the owner applicationId for the set. + *

+ * Note: If {@code purgeOnUninstall} option is enabled, applicationId + * must be specified. + *

+ * + * @param id applicationId owning the set + * @return this DistributedSetBuilder + */ + DistributedSetBuilder withApplicationId(ApplicationId id); + + /** + * Sets a serializer that can be used to serialize + * the elements add to the set. The serializer + * builder should be pre-populated with any classes that will be + * put into the set. + *

+ * Note: This is a mandatory parameter. + *

+ * + * @param serializer serializer + * @return this DistributedSetBuilder + */ + DistributedSetBuilder withSerializer(Serializer serializer); + + /** + * Disables set updates. + *

+ * Attempt to update the built set will throw {@code UnsupportedOperationException}. + * + * @return this DistributedSetBuilder + */ + DistributedSetBuilder withUpdatesDisabled(); + + /** + * Provides weak consistency for set reads. + *

+ * While this can lead to improved read performance, it can also make the behavior + * heard to reason. Only turn this on if you know what you are doing. By default + * reads are strongly consistent. + * + * @return this DistributedSetBuilder + */ + DistributedSetBuilder withRelaxedReadConsistency(); + + /** + * Disables distribution of set entries across multiple database partitions. + *

+ * When partitioning is disabled, the returned set will have a single partition + * that spans the entire cluster. Furthermore, the changes made to the set are + * ephemeral and do not survive a full cluster restart. + *

+ *

+ * Disabling partitions is more appropriate when the returned set is used for + * simple coordination activities and not for long term data persistence. + *

+ *

+ * Note: By default partitions are enabled and entries in the set are durable. + *

+ * @return this DistributedSetBuilder + */ + DistributedSetBuilder withPartitionsDisabled(); + + /** + * Instantiate Metrics service to gather usage and performance metrics. + * By default usage information is enabled + * @return this DistributedSetBuilder + */ + DistributedSetBuilder withMeteringDisabled(); + + /** + * Purges set contents when the application owning the set is uninstalled. + *

+ * When this option is enabled, the caller must provide a applicationId via + * the {@code withAppliationId} builder method. + *

+ * By default set contents will NOT be purged when owning application is uninstalled. + * + * @return this DistributedSetBuilder + */ + DistributedSetBuilder withPurgeOnUninstall(); + + /** + * Builds an set based on the configuration options + * supplied to this builder. + * + * @return new set + * @throws java.lang.RuntimeException if a mandatory parameter is missing + */ + DistributedSet build(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMap.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMap.java new file mode 100644 index 00000000..06395b8e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMap.java @@ -0,0 +1,207 @@ +/* + * 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.Collection; +import java.util.Map; +import java.util.Set; +import java.util.function.BiFunction; + +/** + * A distributed, eventually consistent map. + *

+ * This map does not offer read after writes consistency. Operations are + * serialized via the timestamps issued by the clock service. If two updates + * are in conflict, the update with the more recent timestamp will endure. + *

+ * The interface is mostly similar to {@link java.util.Map} with some minor + * semantic changes and the addition of a listener framework (because the map + * can be mutated by clients on other instances, not only through the local Java + * API). + *

+ * Clients are expected to register an + * {@link EventuallyConsistentMapListener} if they + * are interested in receiving notifications of update to the map. + *

+ * Null values are not allowed in this map. + *

+ */ +public interface EventuallyConsistentMap { + + /** + * Returns the number of key-value mappings in this map. + * + * @return number of key-value mappings + */ + int size(); + + /** + * Returns true if this map is empty. + * + * @return true if this map is empty, otherwise false + */ + boolean isEmpty(); + + /** + * Returns true if the map contains a mapping for the specified key. + * + * @param key the key to check if this map contains + * @return true if this map has a mapping for the key, otherwise false + */ + boolean containsKey(K key); + + /** + * Returns true if the map contains a mapping from any key to the specified + * value. + * + * @param value the value to check if this map has a mapping for + * @return true if this map has a mapping to this value, otherwise false + */ + boolean containsValue(V value); + + /** + * Returns the value mapped to the specified key. + * + * @param key the key to look up in this map + * @return the value mapped to the key, or null if no mapping is found + */ + V get(K key); + + /** + * Associates the specified value to the specified key in this map. + *

+ * Note: this differs from the specification of {@link java.util.Map} + * because it does not return the previous value associated with the key. + * Clients are expected to register an + * {@link EventuallyConsistentMapListener} if + * they are interested in receiving notification of updates to the map. + *

+ * Null values are not allowed in the map. + *

+ * + * @param key the key to add a mapping for in this map + * @param value the value to associate with the key in this map + */ + void put(K key, V value); + + /** + * Removes the mapping associated with the specified key from the map. + *

+ * Clients are expected to register an {@link EventuallyConsistentMapListener} if + * they are interested in receiving notification of updates to the map. + *

+ * + * @param key the key to remove the mapping for + * @return previous value associated with key, or null if there was no mapping for key. + */ + V remove(K key); + + /** + * Removes the given key-value mapping from the map, if it exists. + *

+ * This actually means remove any values up to and including the timestamp + * given by the map's timestampProvider. + * Any mappings that produce an earlier timestamp than this given key-value + * pair will be removed, and any mappings that produce a later timestamp + * will supersede this remove. + *

+ * Note: this differs from the specification of {@link java.util.Map} + * because it does not return a boolean indication whether a value was removed. + * Clients are expected to register an + * {@link EventuallyConsistentMapListener} if + * they are interested in receiving notification of updates to the map. + *

+ * + * @param key the key to remove the mapping for + * @param value the value mapped to the key + */ + void remove(K key, V value); + + /** + * Attempts to compute a mapping for the specified key and its current mapped + * value (or null if there is no current mapping). + *

+ * If the function returns null, the mapping is removed (or remains absent if initially absent). + * @param key map key + * @param recomputeFunction function to recompute a new value + * @return new value + */ + V compute(K key, BiFunction recomputeFunction); + + /** + * Adds mappings for all key-value pairs in the specified map to this map. + *

+ * This will be more efficient in communication than calling individual put + * operations. + *

+ * + * @param m a map of values to add to this map + */ + void putAll(Map m); + + /** + * Removes all mappings from this map. + */ + void clear(); + + /** + * Returns a set of the keys in this map. Changes to the set are not + * reflected back to the map. + * + * @return set of keys in the map + */ + Set keySet(); + + /** + * Returns a collections of values in this map. Changes to the collection + * are not reflected back to the map. + * + * @return collection of values in the map + */ + Collection values(); + + /** + * Returns a set of mappings contained in this map. Changes to the set are + * not reflected back to the map. + * + * @return set of key-value mappings in this map + */ + Set> entrySet(); + + /** + * Adds the specified listener to the map which will be notified whenever + * the mappings in the map are changed. + * + * @param listener listener to register for events + */ + void addListener(EventuallyConsistentMapListener listener); + + /** + * Removes the specified listener from the map such that it will no longer + * receive change notifications. + * + * @param listener listener to deregister for events + */ + void removeListener(EventuallyConsistentMapListener listener); + + /** + * Shuts down the map and breaks communication between different instances. + * This allows the map objects to be cleaned up and garbage collected. + * Calls to any methods on the map subsequent to calling destroy() will + * throw a {@link java.lang.RuntimeException}. + */ + void destroy(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMapBuilder.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMapBuilder.java new file mode 100644 index 00000000..9471321c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMapBuilder.java @@ -0,0 +1,187 @@ +/* + * 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 org.onlab.util.KryoNamespace; +import org.onosproject.cluster.NodeId; +import org.onosproject.store.Timestamp; + +import java.util.Collection; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.function.BiFunction; + +/** + * Builder for eventually consistent maps. + * + * @param type for map keys + * @param type for map values + */ +public interface EventuallyConsistentMapBuilder { + + /** + * Sets the name of the map. + *

+ * Each map is identified by a string map name. EventuallyConsistentMapImpl + * objects in different JVMs that use the same map name will form a + * distributed map across JVMs (provided the cluster service is aware of + * both nodes). + *

+ *

+ * Note: This is a mandatory parameter. + *

+ * + * @param name name of the map + * @return this EventuallyConsistentMapBuilder + */ + EventuallyConsistentMapBuilder withName(String name); + + /** + * Sets a serializer builder that can be used to create a serializer that + * can serialize both the keys and values put into the map. The serializer + * builder should be pre-populated with any classes that will be put into + * the map. + *

+ * Note: This is a mandatory parameter. + *

+ * + * @param serializerBuilder serializer builder + * @return this EventuallyConsistentMapBuilder + */ + EventuallyConsistentMapBuilder withSerializer( + KryoNamespace.Builder serializerBuilder); + + /** + * Sets the function to use for generating timestamps for map updates. + *

+ * The client must provide an {@code BiFunction} + * which can generate timestamps for a given key. The function is free + * to generate timestamps however it wishes, however these timestamps will + * be used to serialize updates to the map so they must be strict enough + * to ensure updates are properly ordered for the use case (i.e. in some + * cases wallclock time will suffice, whereas in other cases logical time + * will be necessary). + *

+ *

+ * Note: This is a mandatory parameter. + *

+ * + * @param timestampProvider provides a new timestamp + * @return this EventuallyConsistentMapBuilder + */ + EventuallyConsistentMapBuilder withTimestampProvider( + BiFunction timestampProvider); + + /** + * Sets the executor to use for processing events coming in from peers. + * + * @param executor event executor + * @return this EventuallyConsistentMapBuilder + */ + EventuallyConsistentMapBuilder withEventExecutor( + ExecutorService executor); + + /** + * Sets the executor to use for sending events to peers. + * + * @param executor event executor + * @return this EventuallyConsistentMapBuilder + */ + EventuallyConsistentMapBuilder withCommunicationExecutor( + ExecutorService executor); + + /** + * Sets the executor to use for background anti-entropy tasks. + * + * @param executor event executor + * @return this EventuallyConsistentMapBuilder + */ + EventuallyConsistentMapBuilder withBackgroundExecutor( + ScheduledExecutorService executor); + + /** + * Sets a function that can determine which peers to replicate updates to. + *

+ * The default function replicates to all nodes. + *

+ * + * @param peerUpdateFunction function that takes a K, V input and returns + * a collection of NodeIds to replicate the event + * to + * @return this EventuallyConsistentMapBuilder + */ + EventuallyConsistentMapBuilder withPeerUpdateFunction( + BiFunction> peerUpdateFunction); + + /** + * Prevents this map from writing tombstones of items that have been + * removed. This may result in zombie items reappearing after they have + * been removed. + *

+ * The default behavior is tombstones are enabled. + *

+ * + * @return this EventuallyConsistentMapBuilder + */ + EventuallyConsistentMapBuilder withTombstonesDisabled(); + + /** + * Configures how often to run the anti-entropy background task. + *

+ * The default anti-entropy period is 5 seconds. + *

+ * + * @param period anti-entropy period + * @param unit time unit for the period + * @return this EventuallyConsistentMapBuilder + */ + EventuallyConsistentMapBuilder withAntiEntropyPeriod( + long period, TimeUnit unit); + + /** + * Configure anti-entropy to converge faster at the cost of doing more work + * for each anti-entropy cycle. Suited to maps with low update rate where + * convergence time is more important than throughput. + *

+ * The default behavior is to do less anti-entropy work at the cost of + * slower convergence. + *

+ * + * @return this EventuallyConsistentMapBuilder + */ + EventuallyConsistentMapBuilder withFasterConvergence(); + + /** + * Configure the map to persist data to disk. + *

+ * The default behavior is no persistence + *

+ * + * @return this EventuallyConsistentMapBuilder + */ + EventuallyConsistentMapBuilder withPersistence(); + + /** + * Builds an eventually consistent map based on the configuration options + * supplied to this builder. + * + * @return new eventually consistent map + * @throws java.lang.RuntimeException if a mandatory parameter is missing + */ + EventuallyConsistentMap build(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMapEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMapEvent.java new file mode 100644 index 00000000..5814534e --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMapEvent.java @@ -0,0 +1,124 @@ +/* + * 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 com.google.common.base.MoreObjects; + +import java.util.Objects; + +/** + * Representation of a EventuallyConsistentMap update notification. + */ +public final class EventuallyConsistentMapEvent { + + public enum Type { + /** + * Entry added to map or existing entry updated. + */ + PUT, + + /** + * Entry removed from map. + */ + REMOVE + } + + private final String name; + private final Type type; + private final K key; + private final V value; + + /** + * Creates a new event object. + * + * @param name map name + * @param type the type of the event + * @param key the key the event concerns + * @param value the value mapped to the key + */ + public EventuallyConsistentMapEvent(String name, Type type, K key, V value) { + this.name = name; + this.type = type; + this.key = key; + this.value = value; + } + + /** + * Returns the map name. + * + * @return name of map + */ + public String name() { + return name; + } + + /** + * Returns the type of the event. + * + * @return the type of the event + */ + public Type type() { + return type; + } + + /** + * Returns the key this event concerns. + * + * @return the key + */ + public K key() { + return key; + } + + /** + * Returns the value associated with this event. If type is REMOVE, + * this is the value that was removed. If type is PUT, this is + * the new value. + * + * @return the value + */ + public V value() { + return value; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof EventuallyConsistentMapEvent)) { + return false; + } + + EventuallyConsistentMapEvent that = (EventuallyConsistentMapEvent) o; + return Objects.equals(this.type, that.type) && + Objects.equals(this.key, that.key) && + Objects.equals(this.value, that.value) && + Objects.equals(this.name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(type, key, value); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("name", name) + .add("type", type) + .add("key", key) + .add("value", value) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMapListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMapListener.java new file mode 100644 index 00000000..b2399a48 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/EventuallyConsistentMapListener.java @@ -0,0 +1,29 @@ +/* + * 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; + +/** + * Listener to be notified about updates to a EventuallyConsistentMap. + */ +public interface EventuallyConsistentMapListener { + + /** + * Reacts to the specified event. + * + * @param event the event + */ + void event(EventuallyConsistentMapEvent event); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/LogicalClockService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/LogicalClockService.java new file mode 100644 index 00000000..7592b126 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/LogicalClockService.java @@ -0,0 +1,35 @@ +/* + * 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 org.onosproject.store.Timestamp; + +/** + * Service that issues logical timestamps. + *

+ * Logical timestamps are useful for establishing a total ordering of + * arbitrary cluster wide events without relying on a fully synchronized + * system clock (wall clock) + */ +public interface LogicalClockService { + + /** + * Generates a new logical timestamp. + * + * @return timestamp + */ + Timestamp getTimestamp(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MapEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MapEvent.java new file mode 100644 index 00000000..6e671351 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MapEvent.java @@ -0,0 +1,135 @@ +/* + * 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.Objects; + +import com.google.common.base.MoreObjects; + +/** + * Representation of a ConsistentMap update notification. + * + * @param key type + * @param value type + */ +public class MapEvent { + + /** + * MapEvent type. + */ + public enum Type { + /** + * Entry inserted into the map. + */ + INSERT, + + /** + * Existing map entry updated. + */ + UPDATE, + + /** + * Entry removed from map. + */ + REMOVE + } + + private final String name; + private final Type type; + private final K key; + private final Versioned value; + + /** + * Creates a new event object. + * + * @param name map name + * @param type type of event + * @param key key the event concerns + * @param value value key is mapped to + */ + public MapEvent(String name, Type type, K key, Versioned value) { + this.name = name; + this.type = type; + this.key = key; + this.value = value; + } + + /** + * Returns the map name. + * + * @return name of map + */ + public String name() { + return name; + } + + /** + * Returns the type of the event. + * + * @return the type of event + */ + public Type type() { + return type; + } + + /** + * Returns the key this event concerns. + * + * @return the key + */ + public K key() { + return key; + } + + /** + * Returns the value associated with this event. If type is REMOVE, + * this is the value that was removed. If type is INSERT/UPDATE, this is + * the new value. + * + * @return the value + */ + public Versioned value() { + return value; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof MapEvent)) { + return false; + } + + MapEvent that = (MapEvent) o; + return Objects.equals(this.name, that.name) && + Objects.equals(this.type, that.type) && + Objects.equals(this.key, that.key) && + Objects.equals(this.value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(name, type, key, value); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("name", name) + .add("type", type) + .add("key", key) + .add("value", value) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MapEventListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MapEventListener.java new file mode 100644 index 00000000..359f4653 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MapEventListener.java @@ -0,0 +1,28 @@ +/* + * 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; + +/** + * Listener to be notified about updates to a ConsistentMap. + */ +public interface MapEventListener { + /** + * Reacts to the specified event. + * + * @param event the event + */ + void event(MapEvent event); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MapInfo.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MapInfo.java new file mode 100644 index 00000000..5db17049 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MapInfo.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.store.service; + +/** + * Metadata information for a consistent map. + */ +public class MapInfo { + private final String name; + private final int size; + + public MapInfo(String name, int size) { + this.name = name; + this.size = size; + } + + /** + * Returns the name of the map. + * + * @return map name + */ + public String name() { + return name; + } + + /** + * Returns the number of entries in the map. + * + * @return map size + */ + public int size() { + return size; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MultiValuedTimestamp.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MultiValuedTimestamp.java new file mode 100644 index 00000000..e068b8e9 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/MultiValuedTimestamp.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.service; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.ComparisonChain; +import org.onosproject.store.Timestamp; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A logical timestamp that derives its value from two input values. The first + * value always takes precedence over the second value when comparing timestamps. + */ +public class MultiValuedTimestamp, U extends Comparable> + implements Timestamp { + + private final T value1; + private final U value2; + + /** + * Creates a new timestamp based on two values. The first value has higher + * precedence than the second when comparing timestamps. + * + * @param value1 first value + * @param value2 second value + */ + public MultiValuedTimestamp(T value1, U value2) { + this.value1 = checkNotNull(value1); + this.value2 = checkNotNull(value2); + } + + @Override + public int compareTo(Timestamp o) { + checkArgument(o instanceof MultiValuedTimestamp, + "Must be MultiValuedTimestamp", o); + MultiValuedTimestamp that = (MultiValuedTimestamp) o; + + return ComparisonChain.start() + .compare(this.value1, that.value1) + .compare(this.value2, that.value2) + .result(); + } + + @Override + public int hashCode() { + return Objects.hash(value1, value2); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof MultiValuedTimestamp)) { + return false; + } + MultiValuedTimestamp that = (MultiValuedTimestamp) obj; + return Objects.equals(this.value1, that.value1) && + Objects.equals(this.value2, that.value2); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("value1", value1) + .add("value2", value2) + .toString(); + } + + /** + * Returns the first value. + * + * @return first value + */ + public T value1() { + return value1; + } + + /** + * Returns the second value. + * + * @return second value + */ + public U value2() { + return value2; + } + + // Default constructor for serialization + @SuppressWarnings("unused") + private MultiValuedTimestamp() { + this.value1 = null; + this.value2 = null; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/PartitionInfo.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/PartitionInfo.java new file mode 100644 index 00000000..a0f06481 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/PartitionInfo.java @@ -0,0 +1,81 @@ +/* + * 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 com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * Contains information about a database partition. + */ +public class PartitionInfo { + private final String name; + private final long term; + private final List members; + private final String leader; + + /** + * Class constructor. + * + * @param name partition name + * @param term term number + * @param members partition members + * @param leader leader name + */ + public PartitionInfo(String name, long term, List members, String leader) { + this.name = name; + this.term = term; + this.members = ImmutableList.copyOf(members); + this.leader = leader; + } + + /** + * Returns the name of the partition. + * + * @return partition name + */ + public String name() { + return name; + } + + /** + * Returns the term number. + * + * @return term number + */ + public long term() { + return term; + } + + /** + * Returns the list of partition members. + * + * @return partition members + */ + public List members() { + return members; + } + + /** + * Returns the partition leader. + * + * @return partition leader + */ + public String leader() { + return leader; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/Serializer.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/Serializer.java new file mode 100644 index 00000000..6245175f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/Serializer.java @@ -0,0 +1,81 @@ +/* + * 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.Arrays; +import java.util.List; + +import org.onlab.util.KryoNamespace; + +import com.google.common.collect.Lists; + +/** + * Interface for serialization of store artifacts. + */ +public interface Serializer { + /** + * Serialize the specified object. + * @param object object to serialize. + * @return serialized bytes. + * @param encoded type + */ + byte[] encode(T object); + + /** + * Deserialize the specified bytes. + * @param bytes byte array to deserialize. + * @return deserialized object. + * @param decoded type + */ + T decode(byte[] bytes); + + /** + * Creates a new Serializer instance from a KryoNamespace. + * + * @param kryo kryo namespace + * @return Serializer instance + */ + static Serializer using(KryoNamespace kryo) { + return using(Arrays.asList(kryo)); + } + + static Serializer using(List namespaces, Class... classes) { + KryoNamespace.Builder builder = new KryoNamespace.Builder(); + namespaces.forEach(builder::register); + Lists.newArrayList(classes).forEach(builder::register); + builder.register(MapEvent.class, MapEvent.Type.class, Versioned.class); + KryoNamespace namespace = builder.build(); + return new Serializer() { + @Override + public byte[] encode(T object) { + return namespace.serialize(object); + } + + @Override + public T decode(byte[] bytes) { + return namespace.deserialize(bytes); + } + }; + } + + static Serializer forTypes(Class... classes) { + return using(KryoNamespace.newBuilder() + .register(classes) + .register(MapEvent.class, MapEvent.Type.class) + .build()); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/SetEvent.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/SetEvent.java new file mode 100644 index 00000000..a869e722 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/SetEvent.java @@ -0,0 +1,113 @@ +/* + * 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.Objects; + +import com.google.common.base.MoreObjects; + +/** + * Representation of a DistributedSet update notification. + * + * @param set element type + */ +public final class SetEvent { + + /** + * SetEvent type. + */ + public enum Type { + /** + * Entry added to the set. + */ + ADD, + + /** + * Entry removed from the set. + */ + REMOVE + } + + private final String name; + private final Type type; + private final E entry; + + /** + * Creates a new event object. + * + * @param name set name + * @param type type of the event + * @param entry entry the event concerns + */ + public SetEvent(String name, Type type, E entry) { + this.name = name; + this.type = type; + this.entry = entry; + } + + /** + * Returns the set name. + * + * @return name of set + */ + public String name() { + return name; + } + + /** + * Returns the type of the event. + * + * @return type of the event + */ + public Type type() { + return type; + } + + /** + * Returns the entry this event concerns. + * + * @return the entry + */ + public E entry() { + return entry; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof SetEvent)) { + return false; + } + + SetEvent that = (SetEvent) o; + return Objects.equals(this.name, that.name) && + Objects.equals(this.type, that.type) && + Objects.equals(this.entry, that.entry); + } + + @Override + public int hashCode() { + return Objects.hash(name, type, entry); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("name", name) + .add("type", type) + .add("entry", entry) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/SetEventListener.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/SetEventListener.java new file mode 100644 index 00000000..a64994ef --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/SetEventListener.java @@ -0,0 +1,28 @@ +/* + * 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; + +/** + * Listener to be notified about updates to a DistributedSet. + */ +public interface SetEventListener { + /** + * Reacts to the specified event. + * + * @param event the event + */ + void event(SetEvent event); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/StorageAdminService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/StorageAdminService.java new file mode 100644 index 00000000..22591044 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/StorageAdminService.java @@ -0,0 +1,75 @@ +/* + * 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.Collection; +import java.util.List; +import java.util.Map; + +/** + * Service for administering storage instances. + */ +public interface StorageAdminService { + + /** + * Returns information about all partitions in the system. + * + * @return list of partition information + */ + List getPartitionInfo(); + + /** + * Returns information about all the consistent maps in the system. + * + * @return list of map information + */ + List getMapInfo(); + + /** + * Returns information about all the atomic counters in the system. + * If 2 counters belonging to 2 different databases have the same name, + * then only one counter from one database is returned. + * + * @return mapping from counter name to that counter's next value + */ + Map getCounters(); + + /** + * Returns information about all the atomic partitioned database counters in the system. + * + * @return mapping from counter name to that counter's next value + */ + Map getPartitionedDatabaseCounters(); + + /** + * Returns information about all the atomic in-memory database counters in the system. + * + * @return mapping from counter name to that counter's next value + */ + Map getInMemoryDatabaseCounters(); + + /** + * Returns all the transactions in the system. + * + * @return collection of transactions + */ + Collection getTransactions(); + + /** + * Redrives stuck transactions while removing those that are done. + */ + void redriveTransactions(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/StorageException.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/StorageException.java new file mode 100644 index 00000000..a66fc3ed --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/StorageException.java @@ -0,0 +1,48 @@ +/* + * 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; + +/** + * Top level exception for Store failures. + */ +@SuppressWarnings("serial") +public class StorageException extends RuntimeException { + public StorageException() { + } + + public StorageException(Throwable t) { + super(t); + } + + /** + * Store operation timeout. + */ + public static class Timeout extends StorageException { + } + + /** + * Store update conflicts with an in flight transaction. + */ + public static class ConcurrentModification extends StorageException { + } + + /** + * Store operation interrupted. + */ + public static class Interrupted extends StorageException { + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/StorageService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/StorageService.java new file mode 100644 index 00000000..f6b411d3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/StorageService.java @@ -0,0 +1,83 @@ +/* + * 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; + +/** + * Storage service. + *

+ * This service provides builders for various distributed primitives. + *

+ * It is expected that services and applications will leverage the primitives indirectly provided by + * this service for their distributed state management and coordination. + */ +public interface StorageService { + + /** + * Creates a new EventuallyConsistentMapBuilder. + * + * @param key type + * @param value type + * @return builder for an eventually consistent map + */ + EventuallyConsistentMapBuilder eventuallyConsistentMapBuilder(); + + /** + * Creates a new ConsistentMapBuilder. + * + * @param key type + * @param value type + * @return builder for a consistent map + */ + ConsistentMapBuilder consistentMapBuilder(); + + /** + * Creates a new DistributedSetBuilder. + * + * @param set element type + * @return builder for an distributed set + */ + DistributedSetBuilder setBuilder(); + + /** + * Creates a new DistributedQueueBuilder. + * + * @param queue entry type + * @return builder for an distributed queue + */ + DistributedQueueBuilder queueBuilder(); + + /** + * Creates a new AtomicCounterBuilder. + * + * @return atomic counter builder + */ + AtomicCounterBuilder atomicCounterBuilder(); + + /** + * Creates a new AtomicValueBuilder. + * + * @param atomic value type + * @return atomic value builder + */ + AtomicValueBuilder atomicValueBuilder(); + + /** + * Creates a new transaction context builder. + * + * @return a builder for a transaction context. + */ + TransactionContextBuilder transactionContextBuilder(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/Transaction.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/Transaction.java new file mode 100644 index 00000000..330d8468 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/Transaction.java @@ -0,0 +1,102 @@ +/* + * 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.List; + +/** + * An immutable transaction object. + */ +public interface Transaction { + + enum State { + /** + * Indicates a new transaction that is about to be prepared. All transactions + * start their life in this state. + */ + PREPARING, + + /** + * Indicates a transaction that is successfully prepared i.e. all participants voted to commit + */ + PREPARED, + + /** + * Indicates a transaction that is about to be committed. + */ + COMMITTING, + + /** + * Indicates a transaction that has successfully committed. + */ + COMMITTED, + + /** + * Indicates a transaction that is about to be rolled back. + */ + ROLLINGBACK, + + /** + * Indicates a transaction that has been rolled back and all locks are released. + */ + ROLLEDBACK + } + + /** + * Returns the transaction Id. + * + * @return transaction id + */ + long id(); + + /** + * Returns the list of updates that are part of this transaction. + * + * @return list of database updates + */ + List updates(); + + /** + * Returns the current state of this transaction. + * + * @return transaction state + */ + State state(); + + /** + * Returns true if this transaction has completed execution. + * + * @return true is yes, false otherwise + */ + default boolean isDone() { + return state() == State.COMMITTED || state() == State.ROLLEDBACK; + } + + /** + * Returns a new transaction that is created by transitioning this one to the specified state. + * + * @param newState destination state + * @return a new transaction instance similar to the current one but its state set to specified state + */ + Transaction transition(State newState); + + /** + * Returns the system time when the transaction was last updated. + * + * @return last update time + */ + long lastUpdated(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContext.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContext.java new file mode 100644 index 00000000..94942e20 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContext.java @@ -0,0 +1,78 @@ +/* + * 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; + +/** + * Provides a context for transactional operations. + *

+ * A transaction context is a vehicle for grouping operations into a unit with the + * properties of atomicity, isolation, and durability. Transactions also provide the + * ability to maintain an application's invariants or integrity constraints, + * supporting the property of consistency. Together these properties are known as ACID. + *

+ * A transaction context provides a boundary within which transactions + * are run. It also is a place where all modifications made within a transaction + * are cached until the point when the transaction commits or aborts. It thus ensures + * isolation of work happening with in the transaction boundary. Within a transaction + * context isolation level is REPEATABLE_READS i.e. only data that is committed can be read. + * The only uncommitted data that can be read is the data modified by the current transaction. + */ +public interface TransactionContext { + + /** + * Returns the unique transactionId. + * + * @return transaction id + */ + long transactionId(); + + /** + * Returns if this transaction context is open. + * + * @return true if open, false otherwise + */ + boolean isOpen(); + + /** + * Starts a new transaction. + */ + void begin(); + + /** + * Commits a transaction that was previously started thereby making its changes permanent + * and externally visible. + * + * @throws TransactionException if transaction fails to commit + */ + void commit(); + + /** + * Aborts any changes made in this transaction context and discarding all locally cached updates. + */ + void abort(); + + /** + * Returns a transactional map data structure with the specified name. + * + * @param key type + * @param value type + * @param mapName name of the transactional map + * @param serializer serializer to use for encoding/decoding keys and values of the map + * @return Transactional Map + */ + TransactionalMap getTransactionalMap(String mapName, Serializer serializer); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContextBuilder.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContextBuilder.java new file mode 100644 index 00000000..e9f3a020 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionContextBuilder.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.store.service; + +/** + * Interface definition for a transaction context builder. + */ +public interface TransactionContextBuilder { + + /** + * Disables distribution of map entries across multiple database partitions. + *

+ * When partitioning is disabled, the returned map will have a single + * partition that spans the entire cluster. Furthermore, the changes made to + * the map are ephemeral and do not survive a full cluster restart. + *

+ *

+ * Note: By default, partitions are enabled. This feature is intended to + * simplify debugging. + *

+ * + * @return this TransactionalContextBuilder + */ + TransactionContextBuilder withPartitionsDisabled(); + + /** + * Builds a TransactionContext based on configuration options supplied to this + * builder. + * + * @return a new TransactionalContext + * @throws java.lang.RuntimeException if a mandatory parameter is missing + */ + TransactionContext build(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionException.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionException.java new file mode 100644 index 00000000..a3723ee7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionException.java @@ -0,0 +1,54 @@ +/* + * 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; + +/** + * Top level exception for Transaction failures. + */ +@SuppressWarnings("serial") +public class TransactionException extends StorageException { + public TransactionException() { + } + + public TransactionException(Throwable t) { + super(t); + } + + /** + * Transaction timeout. + */ + public static class Timeout extends TransactionException { + } + + /** + * Transaction interrupted. + */ + public static class Interrupted extends TransactionException { + } + + /** + * Transaction failure due to optimistic concurrency violation. + */ + public static class OptimisticConcurrencyFailure extends TransactionException { + } + + /** + * Transaction failure due to a conflicting transaction in progress. + */ + public static class ConcurrentModification extends TransactionException { + } +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionalMap.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionalMap.java new file mode 100644 index 00000000..657d9331 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/TransactionalMap.java @@ -0,0 +1,93 @@ +/* + * 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; + +/** + * Transactional Map data structure. + *

+ * A TransactionalMap is created by invoking {@link TransactionContext#getTransactionalMap getTransactionalMap} + * method. All operations performed on this map within a transaction boundary are invisible externally + * until the point when the transaction commits. A commit usually succeeds in the absence of conflicts. + * + * @param type of key. + * @param type of value. + */ +public interface TransactionalMap { + + /** + * Returns the value to which the specified key is mapped, or null if this + * map contains no mapping for the key. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if + * this map contains no mapping for the key + */ + V get(K key); + + /** + * Associates the specified value with the specified key in this map (optional operation). + * If the map previously contained a mapping for the key, the old value is replaced by the + * specified value. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with key, or null if there was + * no mapping for key. + */ + V put(K key, V value); + + /** + * Removes the mapping for a key from this map if it is present (optional operation). + * + * @param key key whose value is to be removed from the map + * @return the value to which this map previously associated the key, + * or null if the map contained no mapping for the key. + */ + V remove(K key); + + /** + * If the specified key is not already associated with a value + * associates it with the given value and returns null, else returns the current value. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the previous value associated with the specified key or null + * if key does not already mapped to a value. + */ + V putIfAbsent(K key, V value); + + /** + * Removes the entry for the specified key only if it is currently + * mapped to the specified value. + * + * @param key key with which the specified value is associated + * @param value value expected to be associated with the specified key + * @return true if the value was removed + */ + boolean remove(K key, V value); + + /** + * Replaces the entry for the specified key only if currently mapped + * to the specified value. + * + * @param key key with which the specified value is associated + * @param oldValue value expected to be associated with the specified key + * @param newValue value to be associated with the specified key + * @return true if the value was replaced + */ + boolean replace(K key, V oldValue, V newValue); +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/Versioned.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/Versioned.java new file mode 100644 index 00000000..89bd3029 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/Versioned.java @@ -0,0 +1,138 @@ +/* + * 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.function.Function; + +import org.joda.time.DateTime; + +import com.google.common.base.MoreObjects; +import com.google.common.base.Objects; + +/** + * Versioned value. + * + * @param value type. + */ +public class Versioned { + + private final V value; + private final long version; + private final long creationTime; + + /** + * Constructs a new versioned value. + * @param value value + * @param version version + * @param creationTime milliseconds of the creation event + * from the Java epoch of 1970-01-01T00:00:00Z + */ + public Versioned(V value, long version, long creationTime) { + this.value = value; + this.version = version; + this.creationTime = creationTime; + } + + /** + * Constructs a new versioned value. + * @param value value + * @param version version + */ + public Versioned(V value, long version) { + this(value, version, System.currentTimeMillis()); + } + + /** + * Returns the value. + * + * @return value. + */ + public V value() { + return value; + } + + /** + * Returns the version. + * + * @return version + */ + public long version() { + return version; + } + + /** + * Returns the system time when this version was created. + *

+ * Care should be taken when relying on creationTime to + * implement any behavior in a distributed setting. Due + * to the possibility of clock skew it is likely that + * even creationTimes of causally related versions can be + * out or order. + * @return creation time + */ + public long creationTime() { + return creationTime; + } + + /** + * Maps this instance into another after transforming its + * value while retaining the same version and creationTime. + * @param transformer function for mapping the value + * @param value type of the returned instance + * @return mapped instance + */ + public Versioned map(Function transformer) { + return new Versioned<>(transformer.apply(value), version, creationTime); + } + + /** + * Returns the value of the specified Versioned object if non-null or else returns + * a default value. + * @param versioned versioned object + * @param defaultValue default value to return if versioned object is null + * @param type of the versioned value + * @return versioned value or default value if versioned object is null + */ + public static U valueOrElse(Versioned versioned, U defaultValue) { + return versioned == null ? defaultValue : versioned.value(); + } + + @Override + public int hashCode() { + return Objects.hashCode(value, version, creationTime); + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof Versioned)) { + return false; + } + Versioned that = (Versioned) other; + return Objects.equal(this.value, that.value) && + Objects.equal(this.version, that.version) && + Objects.equal(this.creationTime, that.creationTime); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("value", value) + .add("version", version) + .add("creationTime", new DateTime(creationTime)) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/WallClockTimestamp.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/WallClockTimestamp.java new file mode 100644 index 00000000..0cc7b453 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/WallClockTimestamp.java @@ -0,0 +1,85 @@ +/* + * Copyright 2014 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 static com.google.common.base.Preconditions.checkArgument; + +import java.util.Objects; + +import org.onosproject.store.Timestamp; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.ComparisonChain; + +/** + * A Timestamp that derives its value from the prevailing + * wallclock time on the controller where it is generated. + */ +public class WallClockTimestamp implements Timestamp { + + private final long unixTimestamp; + + public WallClockTimestamp() { + unixTimestamp = System.currentTimeMillis(); + } + + public WallClockTimestamp(long timestamp) { + unixTimestamp = timestamp; + } + + @Override + public int compareTo(Timestamp o) { + checkArgument(o instanceof WallClockTimestamp, + "Must be WallClockTimestamp", o); + WallClockTimestamp that = (WallClockTimestamp) o; + + return ComparisonChain.start() + .compare(this.unixTimestamp, that.unixTimestamp) + .result(); + } + @Override + public int hashCode() { + return Objects.hash(unixTimestamp); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof WallClockTimestamp)) { + return false; + } + WallClockTimestamp that = (WallClockTimestamp) obj; + return Objects.equals(this.unixTimestamp, that.unixTimestamp); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("unixTimestamp", unixTimestamp) + .toString(); + } + + /** + * Returns the unixTimestamp. + * + * @return unix timestamp + */ + public long unixTimestamp() { + return unixTimestamp; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/package-info.java new file mode 100644 index 00000000..3d86e351 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/store/service/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2014 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. + */ + +/** + * Distributed core state management services. + */ +package org.onosproject.store.service; + diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/JsonUtils.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/JsonUtils.java new file mode 100644 index 00000000..2ebb5545 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/JsonUtils.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.ui; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Provides convenience methods for dealing with JSON nodes, arrays etc. + */ +public final class JsonUtils { + + private static final ObjectMapper MAPPER = new ObjectMapper(); + + // non-instantiable + private JsonUtils() { } + + /** + * Wraps a message payload into an event structure for the given event + * type and sequence ID. Generally, the sequence ID should be a copy of + * the ID from the client request event. + * + * @param type event type + * @param sid sequence ID + * @param payload event payload + * @return the object node representation + */ + public static ObjectNode envelope(String type, long sid, ObjectNode payload) { + ObjectNode event = MAPPER.createObjectNode(); + event.put("event", type); + if (sid > 0) { + event.put("sid", sid); + } + event.set("payload", payload); + return event; + } + + /** + * Composes a message structure for the given message type and payload. + * + * @param type message type + * @param payload message payload + * @return the object node representation + */ + public static ObjectNode envelope(String type, ObjectNode payload) { + ObjectNode event = MAPPER.createObjectNode(); + event.put("event", type); + event.set("payload", payload); + return event; + } + + /** + * Returns the event type from the specified event. + * If the node does not have an "event" property, "unknown" is returned. + * + * @param event message event + * @return extracted event type + */ + public static String eventType(ObjectNode event) { + return string(event, "event", "unknown"); + } + + /** + * Returns the sequence identifier from the specified event, or 0 (zero) + * if the "sid" property does not exist. + * + * @param event message event + * @return extracted sequence identifier + */ + public static long sid(ObjectNode event) { + return number(event, "sid"); + } + + /** + * Returns the payload from the specified event. + * + * @param event message event + * @return extracted payload object + */ + public static ObjectNode payload(ObjectNode event) { + return (ObjectNode) event.path("payload"); + } + + /** + * Returns the specified node property as a number. + * + * @param node message event + * @param name property name + * @return property as number + */ + public static long number(ObjectNode node, String name) { + return node.path(name).asLong(); + } + + /** + * Returns the specified node property as a string. + * + * @param node message event + * @param name property name + * @return property as a string + */ + public static String string(ObjectNode node, String name) { + return node.path(name).asText(); + } + + /** + * Returns the specified node property as a string, with a default fallback. + * + * @param node object node + * @param name property name + * @param defaultValue fallback value if property is absent + * @return property as a string + */ + public static String string(ObjectNode node, String name, String defaultValue) { + return node.path(name).asText(defaultValue); + } + + /** + * Returns the specified node property as an object node. + * + * @param node object node + * @param name property name + * @return property as a node + */ + public static ObjectNode node(ObjectNode node, String name) { + return (ObjectNode) node.path(name); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/RequestHandler.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/RequestHandler.java new file mode 100644 index 00000000..1678923d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/RequestHandler.java @@ -0,0 +1,142 @@ +/* + * 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; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Abstraction of an entity that handles a specific request from the + * user interface client. + * + * @see UiMessageHandler + */ +public abstract class RequestHandler { + + protected static final ObjectMapper MAPPER = new ObjectMapper(); + + private final String eventType; + private UiMessageHandler parent; + + + public RequestHandler(String eventType) { + this.eventType = eventType; + } + + // package private + void setParent(UiMessageHandler parent) { + this.parent = parent; + } + + /** + * Returns the event type that this handler handles. + * + * @return event type + */ + public String eventType() { + return eventType; + } + + /** + * Processes the incoming message payload from the client. + * + * @param sid message sequence identifier + * @param payload request message payload + */ + // TODO: remove sid from signature + public abstract void process(long sid, ObjectNode payload); + + + + // =================================================================== + // === Convenience methods... + + /** + * Returns implementation of the specified service class. + * + * @param serviceClass service class + * @param type of service + * @return implementation class + * @throws org.onlab.osgi.ServiceNotFoundException if no implementation found + */ + protected T get(Class serviceClass) { + return parent.directory().get(serviceClass); + } + + /** + * Sends a message back to the client. + * + * @param eventType message event type + * @param sid message sequence identifier + * @param payload message payload + */ + // TODO: remove sid from signature + protected void sendMessage(String eventType, long sid, ObjectNode payload) { + parent.connection().sendMessage(eventType, sid, payload); + } + + /** + * Sends a message back to the client. + * Here, the message is preformatted; the assumption is it has its + * eventType, sid and payload attributes already filled in. + * + * @param message the message to send + */ + protected void sendMessage(ObjectNode message) { + parent.connection().sendMessage(message); + } + + /** + * Allows one request handler to pass the event on to another for + * further processing. + * Note that the message handlers must be defined in the same parent. + * + * @param eventType event type + * @param sid sequence identifier + * @param payload message payload + */ + // TODO: remove sid from signature + protected void chain(String eventType, long sid, ObjectNode payload) { + parent.exec(eventType, sid, payload); + } + + // =================================================================== + + + /** + * Returns the specified node property as a string. + * + * @param node message event + * @param key property name + * @return property as a string + */ + protected String string(ObjectNode node, String key) { + return JsonUtils.string(node, key); + } + + /** + * Returns the specified node property as a string, with a default fallback. + * + * @param node object node + * @param key property name + * @param defValue fallback value if property is absent + * @return property as a string + */ + protected String string(ObjectNode node, String key, String defValue) { + return JsonUtils.string(node, key, defValue); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiConnection.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiConnection.java new file mode 100644 index 00000000..ead7b0dc --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiConnection.java @@ -0,0 +1,42 @@ +/* + * 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; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Abstraction of a user interface session connection. + */ +public interface UiConnection { + + /** + * Sends the specified JSON message to the user interface client. + * + * @param message message to send + */ + void sendMessage(ObjectNode message); + + /** + * Composes a message into JSON and sends it to the user interface client. + * + * @param type message type + * @param sid message sequence number + * @param payload message payload + */ + // TODO: remove sid parameter + void sendMessage(String type, long sid, ObjectNode payload); + +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiExtension.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiExtension.java new file mode 100644 index 00000000..1f5fbd48 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiExtension.java @@ -0,0 +1,200 @@ +/* + * 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; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * User interface extension. + */ +public final class UiExtension { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private static final String VIEW_PREFIX = "app/view/"; + private static final String EMPTY = ""; + private static final String SLASH = "/"; + private static final String CSS_HTML = "css.html"; + private static final String JS_HTML = "js.html"; + + private final ClassLoader classLoader; + private final String resourcePath; + private final List views; + private final UiMessageHandlerFactory messageHandlerFactory; + private final UiTopoOverlayFactory topoOverlayFactory; + + + // private constructor - only the builder calls this + private UiExtension(ClassLoader cl, String path, List views, + UiMessageHandlerFactory mhFactory, + UiTopoOverlayFactory toFactory) { + this.classLoader = cl; + this.resourcePath = path; + this.views = views; + this.messageHandlerFactory = mhFactory; + this.topoOverlayFactory = toFactory; + } + + + /** + * Returns input stream containing CSS inclusion statements. + * + * @return CSS inclusion statements + */ + public InputStream css() { + return getStream(resourcePath + CSS_HTML); + } + + /** + * Returns input stream containing JavaScript inclusion statements. + * + * @return JavaScript inclusion statements + */ + public InputStream js() { + return getStream(resourcePath + JS_HTML); + } + + /** + * Returns list of user interface views contributed by this extension. + * + * @return contributed view descriptors + */ + public List views() { + return views; + } + + /** + * Returns input stream containing specified view-specific resource. + * + * @param viewId view identifier + * @param path resource path, relative to the view directory + * @return resource input stream + */ + public InputStream resource(String viewId, String path) { + return getStream(VIEW_PREFIX + viewId + SLASH + path); + } + + /** + * Returns message handler factory, if one was defined. + * + * @return message handler factory + */ + public UiMessageHandlerFactory messageHandlerFactory() { + return messageHandlerFactory; + } + + /** + * Returns the topology overlay factory, if one was defined. + * + * @return topology overlay factory + */ + public UiTopoOverlayFactory topoOverlayFactory() { + return topoOverlayFactory; + } + + + // Returns the resource input stream from the specified class-loader. + private InputStream getStream(String path) { + InputStream stream = classLoader.getResourceAsStream(path); + if (stream == null) { + log.warn("Unable to find resource {}", path); + } + return stream; + } + + + /** + * UI Extension Builder. + */ + public static class Builder { + private ClassLoader classLoader; + + private String resourcePath = EMPTY; + private List views = new ArrayList<>(); + private UiMessageHandlerFactory messageHandlerFactory = null; + private UiTopoOverlayFactory topoOverlayFactory = null; + + /** + * Create a builder with the given class loader. + * Resource path defaults to "". + * Views defaults to an empty list. + * Both Message and TopoOverlay factories default to null. + * + * @param cl the class loader + * @param views list of views contributed by this extension + */ + public Builder(ClassLoader cl, List views) { + checkNotNull(cl, "Must provide a class loader"); + checkArgument(views.size() > 0, "Must provide at least one view"); + this.classLoader = cl; + this.views = views; + } + + /** + * Set the resource path. That is, path to where the CSS and JS + * files are located. This value should + * + * @param path resource path + * @return self, for chaining + */ + public Builder resourcePath(String path) { + this.resourcePath = path == null ? EMPTY : path + SLASH; + return this; + } + + /** + * Sets the message handler factory for this extension. + * + * @param mhFactory message handler factory + * @return self, for chaining + */ + public Builder messageHandlerFactory(UiMessageHandlerFactory mhFactory) { + this.messageHandlerFactory = mhFactory; + return this; + } + + /** + * Sets the topology overlay factory for this extension. + * + * @param toFactory topology overlay factory + * @return self, for chaining + */ + public Builder topoOverlayFactory(UiTopoOverlayFactory toFactory) { + this.topoOverlayFactory = toFactory; + return this; + } + + /** + * Builds the UI extension. + * + * @return UI extension instance + */ + public UiExtension build() { + return new UiExtension(classLoader, resourcePath, views, + messageHandlerFactory, topoOverlayFactory); + } + + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiExtensionService.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiExtensionService.java new file mode 100644 index 00000000..330fbb7a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiExtensionService.java @@ -0,0 +1,53 @@ +/* + * 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; + +import java.util.List; + +/** + * Service for registering user interface extensions. + */ +public interface UiExtensionService { + + /** + * Registers the specified user interface extension. + * + * @param extension GUI extension to register + */ + void register(UiExtension extension); + + /** + * Unregisters the specified user interface extension. + * + * @param extension GUI extension to unregister + */ + void unregister(UiExtension extension); + + /** + * Returns the list of user interface extensions. + * + * @return list of extensions + */ + List getExtensions(); + + /** + * Returns the user interface extension that contributed the specified view. + * + * @param viewId view identifier + * @return user interface extension + */ + UiExtension getViewExtension(String viewId); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiMessageHandler.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiMessageHandler.java new file mode 100644 index 00000000..9b9a406c --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiMessageHandler.java @@ -0,0 +1,207 @@ +/* + * 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; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onlab.osgi.ServiceDirectory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Abstraction of an entity capable of processing JSON messages from the user + * interface client. + *

+ * The message structure is: + *

+ *
+ * {
+ *     "type": "event-type",
+ *     "payload": {
+ *         arbitrary JSON object structure
+ *     }
+ * }
+ * 
+ * On {@link #init initialization} the handler will create and cache + * {@link RequestHandler} instances, each of which are bound to a particular + * event-type. On {@link #process arrival} of a new message, + * the event-type is determined, and the message dispatched to the + * corresponding RequestHandler's + * {@link RequestHandler#process process} method. + */ +public abstract class UiMessageHandler { + + private final Logger log = LoggerFactory.getLogger(getClass()); + private final Map handlerMap = new HashMap<>(); + private final ObjectMapper mapper = new ObjectMapper(); + + private UiConnection connection; + private ServiceDirectory directory; + + + /** + * Subclasses must create and return the collection of request handlers + * for the message types they handle. + *

+ * Note that request handlers should be stateless. When we are + * {@link #destroy destroyed}, we will simply drop our references to them + * and allow them to be garbage collected. + * + * @return the message handler instances + */ + protected abstract Collection createRequestHandlers(); + + /** + * Returns the set of message types which this handler is capable of + * processing. + * + * @return set of message types + */ + public Set messageTypes() { + return Collections.unmodifiableSet(handlerMap.keySet()); + } + + /** + * Processes a JSON message from the user interface client. + * + * @param message JSON message + */ + public void process(ObjectNode message) { + String type = JsonUtils.eventType(message); + ObjectNode payload = JsonUtils.payload(message); + // TODO: remove sid + exec(type, 0, payload); + } + + /** + * Finds the appropriate handler and executes the process method. + * + * @param eventType event type + * @param sid sequence identifier + * @param payload message payload + */ + // TODO: remove sid from signature + void exec(String eventType, long sid, ObjectNode payload) { + RequestHandler requestHandler = handlerMap.get(eventType); + if (requestHandler != null) { + requestHandler.process(sid, payload); + } else { + log.warn("no request handler for event type {}", eventType); + } + } + + /** + * Initializes the handler with the user interface connection and + * service directory context. + * + * @param connection user interface connection + * @param directory service directory + */ + public void init(UiConnection connection, ServiceDirectory directory) { + this.connection = connection; + this.directory = directory; + + Collection handlers = createRequestHandlers(); + checkNotNull(handlers, "Handlers cannot be null"); + checkArgument(!handlers.isEmpty(), "Handlers cannot be empty"); + + for (RequestHandler h : handlers) { + h.setParent(this); + handlerMap.put(h.eventType(), h); + } + } + + /** + * Destroys the message handler context. + */ + public void destroy() { + this.connection = null; + this.directory = null; + handlerMap.clear(); + } + + /** + * Returns the user interface connection with which this handler was primed. + * + * @return user interface connection + */ + public UiConnection connection() { + return connection; + } + + /** + * Returns the user interface connection with which this handler was primed. + * + * @return user interface connection + */ + public ServiceDirectory directory() { + return directory; + } + + /** + * Returns implementation of the specified service class. + * + * @param serviceClass service class + * @param type of service + * @return implementation class + * @throws org.onlab.osgi.ServiceNotFoundException if no implementation found + */ + protected T get(Class serviceClass) { + return directory.get(serviceClass); + } + + /** + * Returns a freshly minted object node. + * + * @return new object node + */ + protected ObjectNode objectNode() { + return mapper.createObjectNode(); + } + + /** + * Returns a freshly minted array node. + * + * @return new array node + */ + protected ArrayNode arrayNode() { + return mapper.createArrayNode(); + } + + /** + * Sends the specified data to the client. + * It is expected that the data is in the prescribed JSON format for + * events to the client. + * + * @param data data to be sent + */ + protected synchronized void sendMessage(ObjectNode data) { + UiConnection connection = connection(); + if (connection != null) { + connection.sendMessage(data); + } + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiMessageHandlerFactory.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiMessageHandlerFactory.java new file mode 100644 index 00000000..522daa8f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiMessageHandlerFactory.java @@ -0,0 +1,33 @@ +/* + * 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; + +import java.util.Collection; + +/** + * Abstraction of an entity capable of producing a set of message handlers + * specific to the given user interface connection. + */ +public interface UiMessageHandlerFactory { + + /** + * Produces a collection of new message handlers. + * + * @return collection of new handlers + */ + Collection newHandlers(); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java new file mode 100644 index 00000000..2889422a --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.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.ui; + +import org.onosproject.ui.topo.PropertyPanel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Represents user interface topology view overlay. + */ +public class UiTopoOverlay { + + /** + * Logger for this overlay. + */ + protected final Logger log = LoggerFactory.getLogger(getClass()); + + private final String id; + + private boolean isActive = false; + + /** + * Creates a new user interface topology view overlay descriptor. + * + * @param id overlay identifier + */ + public UiTopoOverlay(String id) { + this.id = id; + } + + /** + * Returns the identifier for this overlay. + * + * @return the identifier + */ + public String id() { + return id; + } + + /** + * Callback invoked to initialize this overlay, soon after creation. + * This default implementation does nothing. + */ + public void init() { + } + + /** + * Callback invoked when this overlay is activated. + */ + public void activate() { + isActive = true; + } + + /** + * Callback invoked when this overlay is deactivated. + */ + public void deactivate() { + isActive = false; + } + + /** + * Returns true if this overlay is currently active. + * + * @return true if overlay active + */ + public boolean isActive() { + return isActive; + } + + /** + * Callback invoked to destroy this instance by cleaning up any + * internal state ready for garbage collection. + * This default implementation holds no state and does nothing. + */ + public void destroy() { + } + + /** + * Callback to modify the contents of the summary panel. + * This default implementation does nothing. + * + * @param pp property panel model of summary data + */ + public void modifySummary(PropertyPanel pp) { + } + + /** + * Callback to modify the contents of the details panel for + * a selected device. + * This default implementation does nothing. + * + * @param pp property panel model of summary data + */ + public void modifyDeviceDetails(PropertyPanel pp) { + } + + /** + * Callback to modify the contents of the details panel for + * a selected host. + * This default implementation does nothing. + * + * @param pp property panel model of summary data + */ + public void modifyHostDetails(PropertyPanel pp) { + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlayFactory.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlayFactory.java new file mode 100644 index 00000000..bd2f2fe6 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiTopoOverlayFactory.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.ui; + +import java.util.Collection; + +/** + * Abstraction of an entity capable of producing one or more topology + * overlay handlers specific to a given user interface connection. + */ +public interface UiTopoOverlayFactory { + + /** + * Produces a collection of new overlay handlers. + * + * @return collection of new overlay handlers + */ + Collection newOverlays(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiView.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiView.java new file mode 100644 index 00000000..2b8b7fa2 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiView.java @@ -0,0 +1,165 @@ +/* + * 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; + +import com.google.common.base.MoreObjects; + +import java.util.Objects; + +/** + * Represents user interface view addition. + */ +public class UiView { + + /** + * Designates navigation menu category. + */ + public enum Category { + /** + * Represents platform related views. + */ + PLATFORM("Platform"), + + /** + * Represents network-control related views. + */ + NETWORK("Network"), + + /** + * Represents miscellaneous views. + */ + OTHER("Other"), + + /** + * Represents views that do not show in the navigation menu. + * This category should not be specified directly; rather, use + * the {@link UiViewHidden} constructor instead of {@link UiView}. + */ + HIDDEN("(hidden)"); + + private final String label; + + Category(String label) { + this.label = label; + } + + /** + * Returns display label for the category. + * + * @return display label + */ + public String label() { + return label; + } + } + + private final Category category; + private final String id; + private final String label; + private final String iconId; + + /** + * Creates a new user interface view descriptor. The navigation item + * will appear in the navigation menu under the specified category. + * + * @param category view category + * @param id view identifier + * @param label view label + */ + public UiView(Category category, String id, String label) { + this(category, id, label, null); + } + + /** + * Creates a new user interface view descriptor. The navigation item + * will appear in the navigation menu under the specified category, + * with the specified icon adornment. + * + * @param category view category + * @param id view identifier + * @param label view label + * @param iconId icon id + */ + public UiView(Category category, String id, String label, String iconId) { + this.category = category; + this.id = id; + this.label = label; + this.iconId = iconId; + } + + /** + * Returns the navigation category. + * + * @return navigation category + */ + public Category category() { + return category; + } + + /** + * Returns the view identifier. + * + * @return view id + */ + public String id() { + return id; + } + + /** + * Returns the view label. + * + * @return view label + */ + public String label() { + return label; + } + + /** + * Returns the icon ID. + * + * @return icon ID + */ + public String iconId() { + return iconId; + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final UiView other = (UiView) obj; + return Objects.equals(this.id, other.id); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("category", category) + .add("id", id) + .add("label", label) + .add("iconId", iconId) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiViewHidden.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiViewHidden.java new file mode 100644 index 00000000..b7fea8fe --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/UiViewHidden.java @@ -0,0 +1,41 @@ +/* + * 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; + +import com.google.common.base.MoreObjects; + +/** + * Represents user interface view addition, except that this one should not + * have an entry in the navigation panel. + */ +public class UiViewHidden extends UiView { + + /** + * Creates a new user interface hidden view descriptor. + * + * @param id view identifier + */ + public UiViewHidden(String id) { + super(Category.HIDDEN, id, null); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("id", id()) + .toString(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/package-info.java new file mode 100644 index 00000000..dd832a59 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/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. + */ + +/** + * Mechanism for managing dynamically registered user interface extensions. + */ +package org.onosproject.ui; diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/CellComparator.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/CellComparator.java new file mode 100644 index 00000000..84d11344 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/CellComparator.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.ui.table; + +/** + * Defines a comparator for cell values. + */ +public interface CellComparator { + + /** + * Compares its two arguments for order. Returns a negative integer, + * zero, or a positive integer as the first argument is less than, equal + * to, or greater than the second.

+ * + * Note that nulls are permitted, and should be sorted to the beginning + * of an ascending sort; i.e. null is considered to be "smaller" than + * non-null values. + * + * @see java.util.Comparator#compare(Object, Object) + * + * @param o1 the first object to be compared. + * @param o2 the second object to be compared. + * @return a negative integer, zero, or a positive integer as the + * first argument is less than, equal to, or greater than the + * second. + * @throws ClassCastException if the arguments' types prevent them from + * being compared by this comparator. + */ + int compare(Object o1, Object o2); + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/CellFormatter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/CellFormatter.java new file mode 100644 index 00000000..854ac27f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/CellFormatter.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.ui.table; + +/** + * Defines a formatter for cell values. + */ +public interface CellFormatter { + + /** + * Formats the specified value into a string appropriate for displaying + * in a table cell. Note that null values are acceptable, and will result + * in the empty string. + * + * @param value the value + * @return the formatted string + */ + String format(Object value); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/TableModel.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/TableModel.java new file mode 100644 index 00000000..d0fccb65 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/TableModel.java @@ -0,0 +1,304 @@ +/* + * 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; + +import com.google.common.collect.Sets; +import org.onosproject.ui.table.cell.DefaultCellComparator; +import org.onosproject.ui.table.cell.DefaultCellFormatter; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A simple model of table data. + *

+ * Note that this is not a full MVC type model; the expected usage pattern + * is to create an empty table, add rows (by consulting the business model), + * sort rows (based on client request parameters), and finally produce the + * sorted list of rows. + *

+ * The table also provides a mechanism for defining how cell values for a + * particular column should be formatted into strings, to help facilitate + * the encoding of the table data into a JSON structure. + *

+ * Note that it is expected that all values for a particular column will + * be the same class. + */ +public class TableModel { + + private static final CellComparator DEF_CMP = DefaultCellComparator.INSTANCE; + private static final CellFormatter DEF_FMT = DefaultCellFormatter.INSTANCE; + + private final String[] columnIds; + private final Set idSet; + private final Map comparators = new HashMap<>(); + private final Map formatters = new HashMap<>(); + private final List rows = new ArrayList<>(); + + + /** + * Constructs a table (devoid of data) with the given column IDs. + * + * @param columnIds column identifiers + */ + public TableModel(String... columnIds) { + checkNotNull(columnIds, "columnIds cannot be null"); + checkArgument(columnIds.length > 0, "must be at least one column"); + + idSet = Sets.newHashSet(columnIds); + if (idSet.size() != columnIds.length) { + throw new IllegalArgumentException("duplicate column ID(s) detected"); + } + + this.columnIds = Arrays.copyOf(columnIds, columnIds.length); + } + + private void checkId(String id) { + checkNotNull(id, "must provide a column ID"); + if (!idSet.contains(id)) { + throw new IllegalArgumentException("unknown column id: " + id); + } + } + + /** + * Returns the number of rows in this table model. + * + * @return number of rows + */ + public int rowCount() { + return rows.size(); + } + + /** + * Returns the number of columns in this table model. + * + * @return number of columns + */ + public int columnCount() { + return columnIds.length; + } + + /** + * Returns the array of column IDs for this table model. + *

+ * Implementation note: we are knowingly passing you a reference to + * our internal array to avoid copying. Don't mess with it. It's your + * table you'll break if you do! + * + * @return the column identifiers + */ + public String[] getColumnIds() { + return columnIds; + } + + /** + * Returns the raw {@link Row} representation of the rows in this table. + * + * @return raw table rows + */ + public Row[] getRows() { + return rows.toArray(new Row[rows.size()]); + } + + /** + * Sets a cell comparator for the specified column. + * + * @param columnId column identifier + * @param comparator comparator to use + */ + public void setComparator(String columnId, CellComparator comparator) { + checkNotNull(comparator, "must provide a comparator"); + checkId(columnId); + comparators.put(columnId, comparator); + } + + /** + * Returns the cell comparator to use on values in the specified column. + * + * @param columnId column identifier + * @return an appropriate cell comparator + */ + private CellComparator getComparator(String columnId) { + checkId(columnId); + CellComparator cmp = comparators.get(columnId); + return cmp == null ? DEF_CMP : cmp; + } + + /** + * Sets a cell formatter for the specified column. + * + * @param columnId column identifier + * @param formatter formatter to use + */ + public void setFormatter(String columnId, CellFormatter formatter) { + checkNotNull(formatter, "must provide a formatter"); + checkId(columnId); + formatters.put(columnId, formatter); + } + + /** + * Returns the cell formatter to use on values in the specified column. + * + * @param columnId column identifier + * @return an appropriate cell formatter + */ + public CellFormatter getFormatter(String columnId) { + checkId(columnId); + CellFormatter fmt = formatters.get(columnId); + return fmt == null ? DEF_FMT : fmt; + } + + /** + * Adds a row to the table model. + * + * @return the row, for chaining + */ + public Row addRow() { + Row r = new Row(); + rows.add(r); + return r; + } + + /** + * Sorts the table rows based on the specified column, in the + * specified direction. + * + * @param columnId column identifier + * @param dir sort direction + */ + public void sort(String columnId, SortDir dir) { + Collections.sort(rows, new RowComparator(columnId, dir)); + } + + + /** Designates sorting direction. */ + public enum SortDir { + /** Designates an ascending sort. */ + ASC, + /** Designates a descending sort. */ + DESC + } + + /** + * Row comparator. + */ + private class RowComparator implements Comparator { + private final String columnId; + private final SortDir dir; + private final CellComparator cellComparator; + + /** + * Constructs a row comparator based on the specified + * column identifier and sort direction. + * + * @param columnId column identifier + * @param dir sort direction + */ + public RowComparator(String columnId, SortDir dir) { + this.columnId = columnId; + this.dir = dir; + cellComparator = getComparator(columnId); + } + + @Override + public int compare(Row a, Row b) { + Object cellA = a.get(columnId); + Object cellB = b.get(columnId); + int result = cellComparator.compare(cellA, cellB); + return dir == SortDir.ASC ? result : -result; + } + } + + /** + * Model of a row. + */ + public class Row { + private final Map cells = new HashMap<>(); + + /** + * Sets the cell value for the given column of this row. + * + * @param columnId column identifier + * @param value value to set + * @return self, for chaining + */ + public Row cell(String columnId, Object value) { + checkId(columnId); + cells.put(columnId, value); + return this; + } + + /** + * Returns the value of the cell in the given column for this row. + * + * @param columnId column identifier + * @return cell value + */ + public Object get(String columnId) { + return cells.get(columnId); + } + + /** + * Returns the value of the cell as a string, using the + * formatter appropriate for the column. + * + * @param columnId column identifier + * @return formatted cell value + */ + String getAsString(String columnId) { + return getFormatter(columnId).format(get(columnId)); + } + + /** + * Returns the row as an array of formatted strings. + * + * @return the formatted row data + */ + public String[] getAsFormattedStrings() { + List formatted = new ArrayList<>(columnCount()); + for (String c : columnIds) { + formatted.add(getAsString(c)); + } + return formatted.toArray(new String[formatted.size()]); + } + } + + private static final String DESC = "desc"; + + /** + * Returns the appropriate sort direction for the given string. + *

+ * The expected strings are "asc" for {@link SortDir#ASC ascending} and + * "desc" for {@link SortDir#DESC descending}. Any other value will + * default to ascending. + * + * @param s sort direction string encoding + * @return sort direction + */ + public static SortDir sortDir(String s) { + return !DESC.equals(s) ? SortDir.ASC : SortDir.DESC; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/TableRequestHandler.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/TableRequestHandler.java new file mode 100644 index 00000000..b8d48575 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/TableRequestHandler.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.ui.table; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.ui.JsonUtils; +import org.onosproject.ui.RequestHandler; + +/** + * Message handler specifically for table views. + */ +public abstract class TableRequestHandler extends RequestHandler { + + private final String respType; + private final String nodeName; + + /** + * Constructs a table request handler for a specific table view. When + * table requests come in, the handler will generate the appropriate + * table rows, sort them according the the request sort parameters, and + * send back the response to the client. + * + * @param reqType type of the request event + * @param respType type of the response event + * @param nodeName name of JSON node holding row data + */ + public TableRequestHandler(String reqType, String respType, String nodeName) { + super(reqType); + this.respType = respType; + this.nodeName = nodeName; + } + + @Override + public void process(long sid, ObjectNode payload) { + TableModel tm = createTableModel(); + populateTable(tm, payload); + + String sortCol = JsonUtils.string(payload, "sortCol", defaultColumnId()); + String sortDir = JsonUtils.string(payload, "sortDir", "asc"); + tm.sort(sortCol, TableModel.sortDir(sortDir)); + + ObjectNode rootNode = MAPPER.createObjectNode(); + rootNode.set(nodeName, TableUtils.generateArrayNode(tm)); + sendMessage(respType, 0, rootNode); + } + + /** + * Creates the table model (devoid of data) using {@link #getColumnIds()} + * to initialize it, ready to be populated. + *

+ * This default implementation returns a table model with default + * formatters and comparators for all columns. + * + * @return an empty table model + */ + protected TableModel createTableModel() { + return new TableModel(getColumnIds()); + } + + /** + * Returns the default column ID to be used when one is not supplied in + * the payload as the column on which to sort. + *

+ * This default implementation returns "id". + * + * @return default sort column identifier + */ + protected String defaultColumnId() { + return "id"; + } + + /** + * Subclasses should return the array of column IDs with which + * to initialize their table model. + * + * @return the column IDs + */ + protected abstract String[] getColumnIds(); + + /** + * Subclasses should populate the table model by adding + * {@link TableModel.Row rows}. + *

+     *     tm.addRow()
+     *         .cell(COL_ONE, ...)
+     *         .cell(COL_TWO, ...)
+     *         ... ;
+     * 
+ * The request payload is provided in case there are request filtering + * parameters (other than sort column and sort direction) that are required + * to generate the appropriate data. + * + * @param tm the table model + * @param payload request payload + */ + protected abstract void populateTable(TableModel tm, ObjectNode payload); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/TableUtils.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/TableUtils.java new file mode 100644 index 00000000..eb2dff78 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/TableUtils.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.ui.table; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Provides static utility methods for dealing with tables. + */ +public final class TableUtils { + + private static final ObjectMapper MAPPER = new ObjectMapper(); + + // non-instantiable + private TableUtils() { } + + /** + * Generates a JSON array node from a table model. + * + * @param tm the table model + * @return the array node representation + */ + public static ArrayNode generateArrayNode(TableModel tm) { + ArrayNode array = MAPPER.createArrayNode(); + for (TableModel.Row r : tm.getRows()) { + array.add(toJsonNode(r, tm)); + } + return array; + } + + private static JsonNode toJsonNode(TableModel.Row row, TableModel tm) { + ObjectNode result = MAPPER.createObjectNode(); + String[] keys = tm.getColumnIds(); + String[] cells = row.getAsFormattedStrings(); + int n = keys.length; + for (int i = 0; i < n; i++) { + result.put(keys[i], cells[i]); + } + return result; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AbstractCellComparator.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AbstractCellComparator.java new file mode 100644 index 00000000..6113fc3f --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AbstractCellComparator.java @@ -0,0 +1,61 @@ +/* + * 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 org.onosproject.ui.table.CellComparator; + +/** + * Base implementation of a {@link CellComparator}. This class takes care + * of dealing with null inputs; subclasses should implement their comparison + * knowing that both inputs are guaranteed to be non-null. + */ +public abstract class AbstractCellComparator implements CellComparator { + + @Override + public int compare(Object o1, Object o2) { + if (o1 == null && o2 == null) { + return 0; // o1 == o2 + } + if (o1 == null) { + return -1; // o1 < o2 + } + if (o2 == null) { + return 1; // o1 > o2 + } + return nonNullCompare(o1, o2); + } + + /** + * Compares its two arguments for order. Returns a negative integer, + * zero, or a positive integer as the first argument is less than, equal + * to, or greater than the second.

+ * + * Note that both objects are guaranteed to be non-null. + * + * @see java.util.Comparator#compare(Object, Object) + * + * @param o1 the first object to be compared. + * @param o2 the second object to be compared. + * @return a negative integer, zero, or a positive integer as the + * first argument is less than, equal to, or greater than the + * second. + * @throws ClassCastException if the arguments' types prevent them from + * being compared by this comparator. + */ + protected abstract int nonNullCompare(Object o1, Object o2); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AbstractCellFormatter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AbstractCellFormatter.java new file mode 100644 index 00000000..33ce2ab5 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AbstractCellFormatter.java @@ -0,0 +1,42 @@ +/* + * 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 org.onosproject.ui.table.CellFormatter; + +/** + * Base implementation of a {@link CellFormatter}. This class takes care of + * dealing with null inputs; subclasses should implement their format method + * knowing that the input is guaranteed to be non-null. + */ +public abstract class AbstractCellFormatter implements CellFormatter { + + @Override + public String format(Object value) { + return value == null ? "" : nonNullFormat(value); + } + + /** + * Formats the specified value into a string appropriate for displaying + * in a table cell. Note that value is guaranteed to be non-null. + * + * @param value the value + * @return the formatted string + */ + protected abstract String nonNullFormat(Object value); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AppIdFormatter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AppIdFormatter.java new file mode 100644 index 00000000..42d684b6 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/AppIdFormatter.java @@ -0,0 +1,41 @@ +/* + * 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 org.onosproject.core.ApplicationId; +import org.onosproject.ui.table.CellFormatter; + +/** + * Formats an application identifier as "(app-id) : (app-name)". + */ +public final class AppIdFormatter extends AbstractCellFormatter { + + // non-instantiable + private AppIdFormatter() { } + + @Override + protected String nonNullFormat(Object value) { + ApplicationId appId = (ApplicationId) value; + return appId.id() + " : " + appId.name(); + } + + /** + * An instance of this class. + */ + public static final CellFormatter INSTANCE = new AppIdFormatter(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/ConnectPointFormatter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/ConnectPointFormatter.java new file mode 100644 index 00000000..fee26154 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/ConnectPointFormatter.java @@ -0,0 +1,41 @@ +/* + * 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 org.onosproject.net.ConnectPoint; +import org.onosproject.ui.table.CellFormatter; + +/** + * Formats a connect point as "(element-id)/(port)". + */ +public final class ConnectPointFormatter extends AbstractCellFormatter { + + // non-instantiable + private ConnectPointFormatter() { } + + @Override + protected String nonNullFormat(Object value) { + ConnectPoint cp = (ConnectPoint) value; + return cp.elementId() + "/" + cp.port(); + } + + /** + * An instance of this class. + */ + public static final CellFormatter INSTANCE = new ConnectPointFormatter(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/DefaultCellComparator.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/DefaultCellComparator.java new file mode 100644 index 00000000..093a20d3 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/DefaultCellComparator.java @@ -0,0 +1,52 @@ +/* + * 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 org.onosproject.ui.table.CellComparator; + +/** + * A default cell comparator. + *

+ * Verifies that the objects being compared are the same class. + * Looks to see if the objects being compared implement comparable and, if so, + * delegates to that; otherwise, implements a lexicographical compare function + * (i.e. string sorting). Uses the objects' toString() method and then + * compares the resulting strings. Note that null values are acceptable and + * are considered "smaller" than any non-null value. + */ +public final class DefaultCellComparator extends AbstractCellComparator { + + // non-instantiable + private DefaultCellComparator() { } + + @Override + @SuppressWarnings("unchecked") + protected int nonNullCompare(Object o1, Object o2) { + if (o1 instanceof Comparable) { + // if o2 is not the same class as o1, then compareTo will + // throw ClassCastException for us + return ((Comparable) o1).compareTo(o2); + } + return o1.toString().compareTo(o2.toString()); + } + + /** + * An instance of this class. + */ + public static final CellComparator INSTANCE = new DefaultCellComparator(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/DefaultCellFormatter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/DefaultCellFormatter.java new file mode 100644 index 00000000..0efa2ebd --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/DefaultCellFormatter.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.ui.table.cell; + +import org.onosproject.ui.table.CellFormatter; + +/** + * A default cell formatter. Uses the object's toString() method. + */ +public final class DefaultCellFormatter extends AbstractCellFormatter { + + // non-instantiable + private DefaultCellFormatter() { } + + @Override + public String nonNullFormat(Object value) { + return value.toString(); + } + + /** + * An instance of this class. + */ + public static final CellFormatter INSTANCE = new DefaultCellFormatter(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/EnumFormatter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/EnumFormatter.java new file mode 100644 index 00000000..5b89a0b7 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/EnumFormatter.java @@ -0,0 +1,40 @@ +/* + * 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 org.onosproject.ui.table.CellFormatter; + +import static org.apache.commons.lang.WordUtils.capitalizeFully; + +/** + * Formats enum types to be readable strings. + */ +public final class EnumFormatter extends AbstractCellFormatter { + + // non-instantiable + private EnumFormatter() { } + + @Override + protected String nonNullFormat(Object value) { + return capitalizeFully(value.toString().replace("_", " ")); + } + + /** + * An instance of this class. + */ + public static final CellFormatter INSTANCE = new EnumFormatter(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/HexFormatter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/HexFormatter.java new file mode 100644 index 00000000..e09982ea --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/HexFormatter.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.ui.table.cell; + +import org.onosproject.ui.table.CellFormatter; + +/** + * Formats integer values as hex strings with a "0x" prefix. + */ +public final class HexFormatter extends AbstractCellFormatter { + + // non-instantiable + private HexFormatter() { } + + @Override + protected String nonNullFormat(Object value) { + return "0x" + Integer.toHexString((Integer) value); + } + + /** + * An instance of this class. + */ + public static final CellFormatter INSTANCE = new HexFormatter(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/HostLocationFormatter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/HostLocationFormatter.java new file mode 100644 index 00000000..fe87c61b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/HostLocationFormatter.java @@ -0,0 +1,41 @@ +/* + * 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 org.onosproject.net.HostLocation; +import org.onosproject.ui.table.CellFormatter; + +/** + * Formats a host location as "(device-id)/(port)". + */ +public final class HostLocationFormatter extends AbstractCellFormatter { + + // non-instantiable + private HostLocationFormatter() { } + + @Override + protected String nonNullFormat(Object value) { + HostLocation loc = (HostLocation) value; + return loc.deviceId() + "/" + loc.port(); + } + + /** + * An instance of this class. + */ + public static final CellFormatter INSTANCE = new HostLocationFormatter(); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/TimeFormatter.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/TimeFormatter.java new file mode 100644 index 00000000..44dc1940 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/TimeFormatter.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.ui.table.cell; + +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; + +import java.util.Locale; + +/** + * Formats time values using {@link DateTimeFormatter}. + */ +public final class TimeFormatter extends AbstractCellFormatter { + + private DateTimeFormatter dtf; + + // NOTE: Unlike other formatters in this package, this one is not + // implemented as a Singleton, because instances may be + // decorated with alternate locale and/or timezone. + + /** + * Constructs a time formatter that uses the default locale and timezone. + */ + public TimeFormatter() { + dtf = DateTimeFormat.longTime(); + } + + /** + * Sets the locale to use for formatting the time. + * + * @param locale locale to use for formatting + * @return self, for chaining + */ + public TimeFormatter withLocale(Locale locale) { + dtf = dtf.withLocale(locale); + return this; + } + + /** + * Sets the time zone to use for formatting the time. + * + * @param zone time zone to use + * @return self, for chaining + */ + public TimeFormatter withZone(DateTimeZone zone) { + dtf = dtf.withZone(zone); + return this; + } + + @Override + protected String nonNullFormat(Object value) { + return dtf.print((DateTime) value); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/package-info.java new file mode 100644 index 00000000..c25bcb06 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/cell/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. + */ + +/** + * Set of table cell renderers and comparators for use by GUI apps. + */ +package org.onosproject.ui.table.cell; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/package-info.java new file mode 100644 index 00000000..ee975d11 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/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. + */ + +/** + * Facilities for creating tabular models of data for the GUI. + */ +package org.onosproject.ui.table; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/AbstractHighlight.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/AbstractHighlight.java new file mode 100644 index 00000000..ab2ced36 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/AbstractHighlight.java @@ -0,0 +1,75 @@ +/* + * 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.topo; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Partial implementation of the highlighting to apply to topology + * view elements. + */ +public abstract class AbstractHighlight { + private final TopoElementType type; + private final String elementId; + private boolean keepSubdued = false; + + /** + * Constructs the highlight. + * + * @param type highlight element type + * @param elementId element identifier + */ + public AbstractHighlight(TopoElementType type, String elementId) { + this.type = checkNotNull(type); + this.elementId = checkNotNull(elementId); + } + + /** + * Sets a flag to tell the renderer to keep this element subdued. + */ + public void keepSubdued() { + keepSubdued = true; + } + + /** + * Returns the element type. + * + * @return element type + */ + public TopoElementType type() { + return type; + } + + /** + * Returns the element identifier. + * + * @return element identifier + */ + public String elementId() { + return elementId; + } + + /** + * Returns the subdued flag. + * + * @return subdued flag + */ + public boolean subdued() { + return keepSubdued; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BaseLink.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BaseLink.java new file mode 100644 index 00000000..c37c129b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BaseLink.java @@ -0,0 +1,43 @@ +/* + * 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.topo; + +import org.onosproject.net.Link; +import org.onosproject.net.LinkKey; + +/** + * A simple concrete implementation of a {@link BiLink}. + * Note that this implementation does not generate any link highlights. + */ +public class BaseLink extends BiLink { + + /** + * Constructs a base link for the given key and initial link. + * + * @param key canonical key for this base link + * @param link first link + */ + public BaseLink(LinkKey key, Link link) { + super(key, link); + } + + @Override + public LinkHighlight highlight(Enum type) { + return null; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BaseLinkMap.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BaseLinkMap.java new file mode 100644 index 00000000..720eca49 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BaseLinkMap.java @@ -0,0 +1,31 @@ +/* + * 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.topo; + +import org.onosproject.net.Link; +import org.onosproject.net.LinkKey; + +/** + * Collection of {@link BaseLink}s. + */ +public class BaseLinkMap extends BiLinkMap { + @Override + public BaseLink create(LinkKey key, Link link) { + return new BaseLink(key, link); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BiLink.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BiLink.java new file mode 100644 index 00000000..8c95e15d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BiLink.java @@ -0,0 +1,104 @@ +/* + * 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.topo; + +import org.onosproject.net.Link; +import org.onosproject.net.LinkKey; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Representation of a link and its inverse, as a partial implementation. + *

+ * Subclasses will decide how to generate the link highlighting (coloring + * and labeling) for the topology view. + */ +public abstract class BiLink { + + private final LinkKey key; + private final Link one; + private Link two; + + /** + * Constructs a bi-link for the given key and initial link. It is expected + * that the caller will have used {@link TopoUtils#canonicalLinkKey(Link)} + * to generate the key. + * + * @param key canonical key for this bi-link + * @param link first link + */ + public BiLink(LinkKey key, Link link) { + this.key = checkNotNull(key); + this.one = checkNotNull(link); + } + + /** + * Sets the second link for this bi-link. + * + * @param link second link + */ + public void setOther(Link link) { + this.two = checkNotNull(link); + } + + /** + * Returns the link identifier in the form expected on the Topology View + * in the web client. + * + * @return link identifier + */ + public String linkId() { + return TopoUtils.compactLinkString(one); + } + + /** + * Returns the key for this bi-link. + * + * @return the key + */ + public LinkKey key() { + return key; + } + + /** + * Returns the first link in this bi-link. + * + * @return the first link + */ + public Link one() { + return one; + } + + /** + * Returns the second link in this bi-link. + * + * @return the second link + */ + public Link two() { + return two; + } + + /** + * Returns the link highlighting to use, based on this bi-link's current + * state. + * + * @param type optional highlighting type parameter + * @return link highlighting model + */ + public abstract LinkHighlight highlight(Enum type); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BiLinkMap.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BiLinkMap.java new file mode 100644 index 00000000..7bc0e65d --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/BiLinkMap.java @@ -0,0 +1,90 @@ +/* + * 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.topo; + +import org.onosproject.net.Link; +import org.onosproject.net.LinkKey; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a collection of {@link BiLink} concrete classes. These maps + * are used to collate a set of unidirectional {@link Link}s into a smaller + * set of bi-directional {@link BiLink} derivatives. + *

+ * @param the type of bi-link subclass + */ +public abstract class BiLinkMap { + + private final Map map = new HashMap<>(); + + /** + * Creates a new instance of a bi-link. Concrete subclasses should + * instantiate and return the appropriate bi-link subclass. + * + * @param key the link key + * @param link the initial link + * @return a new instance + */ + protected abstract B create(LinkKey key, Link link); + + /** + * Adds the given link to our collection, returning the corresponding + * bi-link (creating one if needed necessary). + * + * @param link the link to add to the collection + * @return the corresponding bi-link wrapper + */ + public B add(Link link) { + LinkKey key = TopoUtils.canonicalLinkKey(checkNotNull(link)); + B blink = map.get(key); + if (blink == null) { + // no bi-link yet exists for this link + blink = create(key, link); + map.put(key, blink); + } else { + // we have a bi-link for this link. + if (!blink.one().equals(link)) { + blink.setOther(link); + } + } + return blink; + } + + /** + * Returns the bi-link instances in the collection. + * + * @return the bi-links in this map + */ + public Collection biLinks() { + return map.values(); + } + + /** + * Returns the number of bi-links in the collection. + * + * @return number of bi-links + */ + public int size() { + return map.size(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/ButtonId.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/ButtonId.java new file mode 100644 index 00000000..ca2ecccd --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/ButtonId.java @@ -0,0 +1,70 @@ +/* + * 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.topo; + +import com.google.common.base.MoreObjects; + +/** + * Designates the identity of a button on the topology view panels. + */ +public class ButtonId { + + private final String id; + + /** + * Creates a button ID with the given identifier. + * + * @param id identifier for the button + */ + public ButtonId(String id) { + this.id = id; + } + + /** + * Returns the identifier for this button. + * + * @return identifier + */ + public String id() { + return id; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("id", id()).toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ButtonId that = (ButtonId) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/DeviceHighlight.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/DeviceHighlight.java new file mode 100644 index 00000000..2985d3d4 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/DeviceHighlight.java @@ -0,0 +1,33 @@ +/* + * 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.topo; + +/** + * Denotes the highlighting to apply to a device. + */ +public class DeviceHighlight extends NodeHighlight { + + public DeviceHighlight(String deviceId) { + super(TopoElementType.DEVICE, deviceId); + } + + // TODO: implement device highlighting: + // - visual highlight + // - badging + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/Highlights.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/Highlights.java new file mode 100644 index 00000000..be59c26b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/Highlights.java @@ -0,0 +1,190 @@ +/* + * 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.topo; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Encapsulates highlights to be applied to the topology view, such as + * highlighting links, displaying link labels, perhaps even decorating + * nodes with badges, etc. + */ +public class Highlights { + + private static final String EMPTY = ""; + private static final String MIN = "min"; + private static final String MAX = "max"; + + /** + * A notion of amount. + */ + public enum Amount { + ZERO(EMPTY), + MINIMALLY(MIN), + MAXIMALLY(MAX); + + private final String s; + Amount(String str) { + s = str; + } + + @Override + public String toString() { + return s; + } + } + + private final Map devices = new HashMap<>(); + private final Map hosts = new HashMap<>(); + private final Map links = new HashMap<>(); + + private Amount subdueLevel = Amount.ZERO; + + + /** + * Adds highlighting information for a device. + * + * @param dh device highlight + * @return self, for chaining + */ + public Highlights add(DeviceHighlight dh) { + devices.put(dh.elementId(), dh); + return this; + } + + /** + * Adds highlighting information for a host. + * + * @param hh host highlight + * @return self, for chaining + */ + public Highlights add(HostHighlight hh) { + hosts.put(hh.elementId(), hh); + return this; + } + + /** + * Adds highlighting information for a link. + * + * @param lh link highlight + * @return self, for chaining + */ + public Highlights add(LinkHighlight lh) { + links.put(lh.elementId(), lh); + return this; + } + + /** + * Marks the amount by which all other elements (devices, hosts, links) + * not explicitly referenced here will be "subdued" visually. + * + * @param amount amount to subdue other elements + * @return self, for chaining + */ + public Highlights subdueAllElse(Amount amount) { + subdueLevel = checkNotNull(amount); + return this; + } + + /** + * Returns the collection of device highlights. + * + * @return device highlights + */ + public Collection devices() { + return Collections.unmodifiableCollection(devices.values()); + } + + /** + * Returns the collection of host highlights. + * + * @return host highlights + */ + public Collection hosts() { + return Collections.unmodifiableCollection(hosts.values()); + } + + /** + * Returns the collection of link highlights. + * + * @return link highlights + */ + public Collection links() { + return Collections.unmodifiableCollection(links.values()); + } + + /** + * Returns the amount by which all other elements not explicitly + * referenced here should be "subdued". + * + * @return amount to subdue other elements + */ + public Amount subdueLevel() { + return subdueLevel; + } + + /** + * Returns the node highlight (device or host) for the given element + * identifier, or null if no match. + * + * @param id element identifier + * @return corresponding node highlight + */ + public NodeHighlight getNode(String id) { + NodeHighlight nh = devices.get(id); + return nh != null ? nh : hosts.get(id); + } + + /** + * Returns the device highlight for the given device identifier, + * or null if no match. + * + * @param id device identifier + * @return corresponding device highlight + */ + public DeviceHighlight getDevice(String id) { + return devices.get(id); + } + + /** + * Returns the host highlight for the given host identifier, + * or null if no match. + * + * @param id host identifier + * @return corresponding host highlight + */ + public HostHighlight getHost(String id) { + return hosts.get(id); + } + + /** + * Returns the link highlight for the given link identifier, + * or null if no match. + * + * @param id link identifier + * @return corresponding link highlight + */ + public LinkHighlight getLink(String id) { + return links.get(id); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/HostHighlight.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/HostHighlight.java new file mode 100644 index 00000000..76669a84 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/HostHighlight.java @@ -0,0 +1,33 @@ +/* + * 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.topo; + +/** + * Denotes the highlighting to apply to a host. + */ +public class HostHighlight extends NodeHighlight { + + public HostHighlight(String hostId) { + super(TopoElementType.HOST, hostId); + } + + // TODO: implement host highlighting: + // - visual highlight + // - badging + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/LinkHighlight.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/LinkHighlight.java new file mode 100644 index 00000000..b4e43304 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/LinkHighlight.java @@ -0,0 +1,147 @@ +/* + * 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.topo; + +import java.util.Collections; +import java.util.Set; +import java.util.TreeSet; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Denotes the highlighting to be applied to a link. + * {@link Flavor} is a closed set of NO-, PRIMARY-, or SECONDARY- highlighting. + * {@link Mod} is an open ended set of additional modifications (CSS classes) + * that may also be applied. + * Note that {@link #MOD_OPTICAL} and {@link #MOD_ANIMATED} are pre-defined mods. + * Label text may be set, which will also be displayed on the link. + */ +public class LinkHighlight extends AbstractHighlight { + + private static final String PLAIN = "plain"; + private static final String PRIMARY = "primary"; + private static final String SECONDARY = "secondary"; + private static final String EMPTY = ""; + private static final String SPACE = " "; + + private final Flavor flavor; + private final Set mods = new TreeSet<>(); + private String label = EMPTY; + + /** + * Constructs a link highlight entity. + * + * @param linkId the link identifier + * @param flavor the highlight flavor + */ + public LinkHighlight(String linkId, Flavor flavor) { + super(TopoElementType.LINK, linkId); + this.flavor = checkNotNull(flavor); + } + + /** + * Adds a highlighting modification to this link highlight. + * + * @param mod mod to be added + * @return self, for chaining + */ + public LinkHighlight addMod(Mod mod) { + mods.add(checkNotNull(mod)); + return this; + } + + /** + * Adds a label to be displayed on the link. + * + * @param label the label text + * @return self, for chaining + */ + public LinkHighlight setLabel(String label) { + this.label = label == null ? EMPTY : label; + return this; + } + + /** + * Returns the highlight flavor. + * + * @return highlight flavor + */ + public Flavor flavor() { + return flavor; + } + + /** + * Returns the highlight modifications. + * + * @return highlight modifications + */ + public Set mods() { + return Collections.unmodifiableSet(mods); + } + + /** + * Generates the CSS classes string from the {@link #flavor} and + * any optional {@link #mods}. + * + * @return CSS classes string + */ + public String cssClasses() { + StringBuilder sb = new StringBuilder(flavor.toString()); + mods.forEach(m -> sb.append(SPACE).append(m)); + return sb.toString(); + } + + /** + * Returns the label text. + * + * @return label text + */ + public String label() { + return label; + } + + /** + * Link highlighting flavor. + */ + public enum Flavor { + NO_HIGHLIGHT(PLAIN), + PRIMARY_HIGHLIGHT(PRIMARY), + SECONDARY_HIGHLIGHT(SECONDARY); + + private String cssName; + + Flavor(String s) { + cssName = s; + } + + @Override + public String toString() { + return cssName; + } + } + + /** + * Denotes a link to be tagged as an optical link. + */ + public static final Mod MOD_OPTICAL = new Mod("optical"); + + /** + * Denotes a link to be tagged with animated traffic ("marching ants"). + */ + public static final Mod MOD_ANIMATED = new Mod("animated"); +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/Mod.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/Mod.java new file mode 100644 index 00000000..d21a8724 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/Mod.java @@ -0,0 +1,66 @@ +/* + * 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.topo; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Highlighting modification. + *

+ * Note that (for link highlights) this translates to a CSS class name + * that is applied to the link in the Topology UI. + */ +public final class Mod implements Comparable { + private final String modId; + + /** + * Constructs a mod with the given identifier. + * + * @param modId modification identifier + */ + public Mod(String modId) { + this.modId = checkNotNull(modId); + } + + @Override + public String toString() { + return modId; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Mod mod = (Mod) o; + return modId.equals(mod.modId); + } + + @Override + public int hashCode() { + return modId.hashCode(); + } + + @Override + public int compareTo(Mod o) { + return this.modId.compareTo(o.modId); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeHighlight.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeHighlight.java new file mode 100644 index 00000000..735f8166 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeHighlight.java @@ -0,0 +1,27 @@ +/* + * 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.topo; + +/** + * Parent class of {@link DeviceHighlight} and {@link HostHighlight}. + */ +public abstract class NodeHighlight extends AbstractHighlight { + public NodeHighlight(TopoElementType type, String elementId) { + super(type, elementId); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeSelection.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeSelection.java new file mode 100644 index 00000000..b284de1b --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/NodeSelection.java @@ -0,0 +1,252 @@ +/* + * 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.topo; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.net.Device; +import org.onosproject.net.Element; +import org.onosproject.net.Host; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.host.HostService; +import org.onosproject.ui.JsonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.HostId.hostId; + +/** + * Encapsulates a selection of devices and/or hosts from the topology view. + */ +public class NodeSelection { + + private static final Logger log = + LoggerFactory.getLogger(NodeSelection.class); + + private static final String IDS = "ids"; + private static final String HOVER = "hover"; + + private final DeviceService deviceService; + private final HostService hostService; + + private final Set ids; + private final String hover; + + private final Set devices = new HashSet<>(); + private final Set hosts = new HashSet<>(); + private Element hovered; + + /** + * Creates a node selection entity, from the given payload, using the + * supplied device and host services. Note that if a device or host was + * hovered over by the mouse, it is available via {@link #hovered()}. + * + * @param payload message payload + * @param deviceService device service + * @param hostService host service + */ + public NodeSelection(ObjectNode payload, + DeviceService deviceService, + HostService hostService) { + this.deviceService = deviceService; + this.hostService = hostService; + + ids = extractIds(payload); + hover = extractHover(payload); + + // start by extracting the hovered element if any + if (isNullOrEmpty(hover)) { + hovered = null; + } else { + setHoveredElement(); + } + + // now go find the devices and hosts that are in the selection list + Set unmatched = findDevices(ids); + unmatched = findHosts(unmatched); + if (unmatched.size() > 0) { + log.debug("Skipping unmatched IDs {}", unmatched); + } + + } + + /** + * Returns a view of the selected devices (hover not included). + * + * @return selected devices + */ + public Set devices() { + return Collections.unmodifiableSet(devices); + } + + /** + * Returns a view of the selected devices, including the hovered device + * if there was one. + * + * @return selected (plus hovered) devices + */ + public Set devicesWithHover() { + Set withHover; + if (hovered != null && hovered instanceof Device) { + withHover = new HashSet<>(devices); + withHover.add((Device) hovered); + } else { + withHover = devices; + } + return Collections.unmodifiableSet(withHover); + } + + /** + * Returns a view of the selected hosts (hover not included). + * + * @return selected hosts + */ + public Set hosts() { + return Collections.unmodifiableSet(hosts); + } + + /** + * Returns a view of the selected hosts, including the hovered host + * if thee was one. + * + * @return selected (plus hovered) hosts + */ + public Set hostsWithHover() { + Set withHover; + if (hovered != null && hovered instanceof Host) { + withHover = new HashSet<>(hosts); + withHover.add((Host) hovered); + } else { + withHover = hosts; + } + return Collections.unmodifiableSet(withHover); + } + + /** + * Returns the element (host or device) over which the mouse was hovering, + * or null. + * + * @return element hovered over + */ + public Element hovered() { + return hovered; + } + + /** + * Returns true if nothing is selected. + * + * @return true if nothing selected + */ + public boolean none() { + return devices().size() == 0 && hosts().size() == 0; + } + + @Override + public String toString() { + return "NodeSelection{" + + "ids=" + ids + + ", hover='" + hover + '\'' + + ", #devices=" + devices.size() + + ", #hosts=" + hosts.size() + + '}'; + } + + // == helper methods + + private Set extractIds(ObjectNode payload) { + ArrayNode array = (ArrayNode) payload.path(IDS); + if (array == null || array.size() == 0) { + return Collections.emptySet(); + } + + Set ids = new HashSet<>(); + for (JsonNode node : array) { + ids.add(node.asText()); + } + return ids; + } + + private String extractHover(ObjectNode payload) { + return JsonUtils.string(payload, HOVER); + } + + private void setHoveredElement() { + Set unmatched; + unmatched = new HashSet<>(); + unmatched.add(hover); + unmatched = findDevices(unmatched); + if (devices.size() == 1) { + hovered = devices.iterator().next(); + devices.clear(); + } else { + unmatched = findHosts(unmatched); + if (hosts.size() == 1) { + hovered = hosts.iterator().next(); + hosts.clear(); + } else { + hovered = null; + log.debug("Skipping unmatched HOVER {}", unmatched); + } + } + } + + private Set findDevices(Set ids) { + Set unmatched = new HashSet<>(); + Device device; + + for (String id : ids) { + try { + device = deviceService.getDevice(deviceId(id)); + if (device != null) { + devices.add(device); + } else { + unmatched.add(id); + } + } catch (Exception e) { + unmatched.add(id); + } + } + return unmatched; + } + + private Set findHosts(Set ids) { + Set unmatched = new HashSet<>(); + Host host; + + for (String id : ids) { + try { + host = hostService.getHost(hostId(id)); + if (host != null) { + hosts.add(host); + } else { + unmatched.add(id); + } + } catch (Exception e) { + unmatched.add(id); + } + } + return unmatched; + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/PropertyPanel.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/PropertyPanel.java new file mode 100644 index 00000000..121e0834 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/PropertyPanel.java @@ -0,0 +1,353 @@ +/* + * 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.topo; + +import com.google.common.collect.Sets; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Models a panel displayed on the Topology View. + */ +public class PropertyPanel { + + private static final DecimalFormat DF0 = new DecimalFormat("#,###"); + + private String title; + private String typeId; + private String id; + private List properties = new ArrayList<>(); + private List buttons = new ArrayList<>(); + + /** + * Constructs a property panel model with the given title and + * type identifier (icon to display). + * + * @param title title text + * @param typeId type (icon) ID + */ + public PropertyPanel(String title, String typeId) { + this.title = title; + this.typeId = typeId; + } + + /** + * Adds an ID field to the panel data, to be included in + * the returned JSON data to the client. + * + * @param id the identifier + * @return self, for chaining + */ + public PropertyPanel id(String id) { + this.id = id; + return this; + } + + /** + * Adds a property to the panel data. + * + * @param key property key + * @param value property value + * @return self, for chaining + */ + public PropertyPanel addProp(String key, String value) { + properties.add(new Prop(key, value)); + return this; + } + + /** + * Adds a property to the panel data, using a decimal formatter. + * + * @param key property key + * @param value property value + * @return self, for chaining + */ + public PropertyPanel addProp(String key, int value) { + properties.add(new Prop(key, DF0.format(value))); + return this; + } + + /** + * Adds a property to the panel data, using a decimal formatter. + * + * @param key property key + * @param value property value + * @return self, for chaining + */ + public PropertyPanel addProp(String key, long value) { + properties.add(new Prop(key, DF0.format(value))); + return this; + } + + /** + * Adds a property to the panel data. Note that the value's + * {@link Object#toString toString()} method is used to convert the + * value to a string. + * + * @param key property key + * @param value property value + * @return self, for chaining + */ + public PropertyPanel addProp(String key, Object value) { + properties.add(new Prop(key, value.toString())); + return this; + } + + /** + * Adds a property to the panel data. Note that the value's + * {@link Object#toString toString()} method is used to convert the + * value to a string, from which the characters defined in the given + * regular expression string are stripped. + * + * @param key property key + * @param value property value + * @param reStrip regexp characters to strip from value string + * @return self, for chaining + */ + public PropertyPanel addProp(String key, Object value, String reStrip) { + String val = value.toString().replaceAll(reStrip, ""); + properties.add(new Prop(key, val)); + return this; + } + + /** + * Adds a separator to the panel data. + * + * @return self, for chaining + */ + public PropertyPanel addSeparator() { + properties.add(new Separator()); + return this; + } + + /** + * Returns the title text. + * + * @return title text + */ + public String title() { + return title; + } + + /** + * Returns the type identifier. + * + * @return type identifier + */ + public String typeId() { + return typeId; + } + + /** + * Returns the internal ID. + * + * @return the ID + */ + public String id() { + return id; + } + + /** + * Returns the list of properties to be displayed. + * + * @return the property list + */ + // TODO: consider protecting this? + public List properties() { + return properties; + } + + /** + * Returns the list of button descriptors. + * + * @return the button list + */ + // TODO: consider protecting this? + public List buttons() { + return buttons; + } + + // == MUTATORS + + /** + * Sets the title text. + * + * @param title title text + * @return self, for chaining + */ + public PropertyPanel title(String title) { + this.title = title; + return this; + } + + /** + * Sets the type identifier (icon ID). + * + * @param typeId type identifier + * @return self, for chaining + */ + public PropertyPanel typeId(String typeId) { + this.typeId = typeId; + return this; + } + + /** + * Removes properties with the given keys from the list. + * + * @param keys keys of properties to remove + * @return self, for chaining + */ + public PropertyPanel removeProps(String... keys) { + Set forRemoval = Sets.newHashSet(keys); + List toKeep = new ArrayList<>(); + for (Prop p: properties) { + if (!forRemoval.contains(p.key())) { + toKeep.add(p); + } + } + properties = toKeep; + return this; + } + + /** + * Removes all currently defined properties. + * + * @return self, for chaining + */ + public PropertyPanel removeAllProps() { + properties.clear(); + return this; + } + + /** + * Adds the given button descriptor to the panel data. + * + * @param button button descriptor + * @return self, for chaining + */ + public PropertyPanel addButton(ButtonId button) { + buttons.add(button); + return this; + } + + /** + * Removes buttons with the given descriptors from the list. + * + * @param descriptors descriptors to remove + * @return self, for chaining + */ + public PropertyPanel removeButtons(ButtonId... descriptors) { + Set forRemoval = Sets.newHashSet(descriptors); + List toKeep = new ArrayList<>(); + for (ButtonId bd: buttons) { + if (!forRemoval.contains(bd)) { + toKeep.add(bd); + } + } + buttons = toKeep; + return this; + } + + /** + * Removes all currently defined buttons. + * + * @return self, for chaining + */ + public PropertyPanel removeAllButtons() { + buttons.clear(); + return this; + } + + // ==================== + + + /** + * Simple data carrier for a property, composed of a key/value pair. + */ + public static class Prop { + private final String key; + private final String value; + + /** + * Constructs a property data value. + * + * @param key property key + * @param value property value + */ + public Prop(String key, String value) { + this.key = key; + this.value = value; + } + + /** + * Returns the property's key. + * + * @return the key + */ + public String key() { + return key; + } + + /** + * Returns the property's value. + * + * @return the value + */ + public String value() { + return value; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Prop prop = (Prop) o; + return key.equals(prop.key) && value.equals(prop.value); + } + + @Override + public int hashCode() { + int result = key.hashCode(); + result = 31 * result + value.hashCode(); + return result; + } + + @Override + public String toString() { + return "{" + key + " -> " + value + "}"; + } + } + + /** + * Auxiliary class representing a separator property. + */ + public static class Separator extends Prop { + public Separator() { + super("-", ""); + } + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoConstants.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoConstants.java new file mode 100644 index 00000000..38a8f036 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoConstants.java @@ -0,0 +1,129 @@ +/* + * 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.topo; + +/** + * Defines string constants used in the Topology View of the ONOS GUI. + *

+ * See also: + *

    + *
  • https://wiki.onosproject.org/display/ONOS/UI+Service+-+GlyphService
  • + *
+ */ +public final class TopoConstants { + + /** + * Defines constants for standard glyph identifiers. + */ + public static final class Glyphs { + public static final String UNKNOWN = "unknown"; + public static final String BIRD = "bird"; + public static final String NODE = "node"; + public static final String SWITCH = "switch"; + public static final String ROADM = "roadm"; + public static final String ENDSTATION = "endstation"; + public static final String ROUTER = "router"; + public static final String BGP_SPEAKER = "bgpSpeaker"; + public static final String CHAIN = "chain"; + public static final String CROWN = "crown"; + public static final String TOPO = "topo"; + public static final String REFRESH = "refresh"; + public static final String GARBAGE = "garbage"; + public static final String FLOW_TABLE = "flowTable"; + public static final String PORT_TABLE = "portTable"; + public static final String GROUP_TABLE = "groupTable"; + public static final String SUMMARY = "summary"; + public static final String DETAILS = "details"; + public static final String PORTS = "ports"; + public static final String MAP = "map"; + public static final String CYCLE_LABELS = "cycleLabels"; + public static final String OBLIQUE = "oblique"; + public static final String FILTERS = "filters"; + public static final String RESET_ZOOM = "resetZoom"; + public static final String RELATED_INTENTS = "relatedIntents"; + public static final String NEXT_INTENT = "nextIntent"; + public static final String PREV_INTENT = "prevIntent"; + public static final String INTENT_TRAFFIC = "intentTraffic"; + public static final String ALL_TRAFFIC = "allTraffic"; + public static final String FLOWS = "flows"; + public static final String EQ_MASTER = "eqMaster"; + public static final String UI_ATTACHED = "uiAttached"; + public static final String CHECK_MARK = "checkMark"; + public static final String X_MARK = "xMark"; + public static final String TRIANGLE_UP = "triangleUp"; + public static final String TRIANGLE_DOWN = "triangleDown"; + public static final String PLUS = "plus"; + public static final String MINUS = "minus"; + public static final String PLAY = "play"; + public static final String STOP = "stop"; + public static final String CLOUD = "cloud"; + } + + /** + * Defines constants for property names on the default summary and + * details panels. + */ + public static final class Properties { + public static final String SEPARATOR = "-"; + + // summary panel + public static final String DEVICES = "Devices"; + public static final String LINKS = "Links"; + public static final String HOSTS = "Hosts"; + public static final String TOPOLOGY_SSCS = "Topology SCCs"; + public static final String INTENTS = "Intents"; + public static final String TUNNELS = "Tunnels"; + public static final String FLOWS = "Flows"; + public static final String VERSION = "Version"; + + // device details + public static final String URI = "URI"; + public static final String VENDOR = "Vendor"; + public static final String HW_VERSION = "H/W Version"; + public static final String SW_VERSION = "S/W Version"; + public static final String SERIAL_NUMBER = "Serial Number"; + public static final String PROTOCOL = "Protocol"; + public static final String LATITUDE = "Latitude"; + public static final String LONGITUDE = "Longitude"; + public static final String PORTS = "Ports"; + + // host details + public static final String MAC = "MAC"; + public static final String IP = "IP"; + public static final String VLAN = "VLAN"; + } + + /** + * Defines identities of core buttons that appear on the topology + * details panel. + */ + public static final class CoreButtons { + public static final ButtonId SHOW_DEVICE_VIEW = + new ButtonId("showDeviceView"); + + public static final ButtonId SHOW_FLOW_VIEW = + new ButtonId("showFlowView"); + + public static final ButtonId SHOW_PORT_VIEW = + new ButtonId("showPortView"); + + public static final ButtonId SHOW_GROUP_VIEW = + new ButtonId("showGroupView"); + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoElementType.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoElementType.java new file mode 100644 index 00000000..dc327464 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoElementType.java @@ -0,0 +1,25 @@ +/* + * 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.topo; + +/** + * The topology element types to which a highlight can be applied. + */ +public enum TopoElementType { + DEVICE, HOST, LINK +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java new file mode 100644 index 00000000..a94068ee --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java @@ -0,0 +1,160 @@ +/* + * 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.topo; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static org.onosproject.ui.JsonUtils.envelope; + +/** + * JSON utilities for the Topology View. + */ +public final class TopoJson { + // package-private for unit test access + static final String SHOW_HIGHLIGHTS = "showHighlights"; + + static final String DEVICES = "devices"; + static final String HOSTS = "hosts"; + static final String LINKS = "links"; + static final String SUBDUE = "subdue"; + + static final String ID = "id"; + static final String LABEL = "label"; + static final String CSS = "css"; + + static final String TITLE = "title"; + static final String TYPE = "type"; + static final String PROP_ORDER = "propOrder"; + static final String PROPS = "props"; + static final String BUTTONS = "buttons"; + + + private static final ObjectMapper MAPPER = new ObjectMapper(); + + private static ObjectNode objectNode() { + return MAPPER.createObjectNode(); + } + + private static ArrayNode arrayNode() { + return MAPPER.createArrayNode(); + } + + // non-instantiable + private TopoJson() { } + + /** + * Returns a formatted message ready to send to the topology view + * to render highlights. + * + * @param highlights highlights model to transform + * @return fully formatted "show highlights" message + */ + public static ObjectNode highlightsMessage(Highlights highlights) { + return envelope(SHOW_HIGHLIGHTS, json(highlights)); + } + + /** + * Transforms the given highlights model into a JSON message payload. + * + * @param highlights the model to transform + * @return JSON payload + */ + public static ObjectNode json(Highlights highlights) { + ObjectNode payload = objectNode(); + + ArrayNode devices = arrayNode(); + ArrayNode hosts = arrayNode(); + ArrayNode links = arrayNode(); + + payload.set(DEVICES, devices); + payload.set(HOSTS, hosts); + payload.set(LINKS, links); + + highlights.devices().forEach(dh -> devices.add(json(dh))); + highlights.hosts().forEach(hh -> hosts.add(json(hh))); + highlights.links().forEach(lh -> links.add(json(lh))); + + Highlights.Amount toSubdue = highlights.subdueLevel(); + if (!toSubdue.equals(Highlights.Amount.ZERO)) { + payload.put(SUBDUE, toSubdue.toString()); + } + return payload; + } + + private static ObjectNode json(DeviceHighlight dh) { + ObjectNode n = objectNode() + .put(ID, dh.elementId()); + if (dh.subdued()) { + n.put(SUBDUE, true); + } + return n; + } + + private static ObjectNode json(HostHighlight hh) { + ObjectNode n = objectNode() + .put(ID, hh.elementId()); + if (hh.subdued()) { + n.put(SUBDUE, true); + } + return n; + } + + private static ObjectNode json(LinkHighlight lh) { + ObjectNode n = objectNode() + .put(ID, lh.elementId()) + .put(LABEL, lh.label()) + .put(CSS, lh.cssClasses()); + if (lh.subdued()) { + n.put(SUBDUE, true); + } + return n; + } + + /** + * Translates the given property panel into JSON, for returning + * to the client. + * + * @param pp the property panel model + * @return JSON payload + */ + public static ObjectNode json(PropertyPanel pp) { + ObjectNode result = objectNode() + .put(TITLE, pp.title()) + .put(TYPE, pp.typeId()) + .put(ID, pp.id()); + + ObjectNode pnode = objectNode(); + ArrayNode porder = arrayNode(); + for (PropertyPanel.Prop p : pp.properties()) { + porder.add(p.key()); + pnode.put(p.key(), p.value()); + } + result.set(PROP_ORDER, porder); + result.set(PROPS, pnode); + + ArrayNode buttons = arrayNode(); + for (ButtonId b : pp.buttons()) { + buttons.add(b.id()); + } + result.set(BUTTONS, buttons); + return result; + } + +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoUtils.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoUtils.java new file mode 100644 index 00000000..f92d5798 --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/TopoUtils.java @@ -0,0 +1,159 @@ +/* + * 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.topo; + +import org.onosproject.net.Link; +import org.onosproject.net.LinkKey; + +import java.text.DecimalFormat; + +import static org.onosproject.net.LinkKey.linkKey; + +/** + * Utility methods for helping out with formatting data for the Topology View + * in the web client. + */ +public final class TopoUtils { + + // explicit decision made to not 'javadoc' these self explanatory constants + public static final double KILO = 1024; + public static final double MEGA = 1024 * KILO; + public static final double GIGA = 1024 * MEGA; + + public static final String GBITS_UNIT = "Gb"; + public static final String MBITS_UNIT = "Mb"; + public static final String KBITS_UNIT = "Kb"; + public static final String BITS_UNIT = "b"; + public static final String GBYTES_UNIT = "GB"; + public static final String MBYTES_UNIT = "MB"; + public static final String KBYTES_UNIT = "KB"; + public static final String BYTES_UNIT = "B"; + + + private static final DecimalFormat DF2 = new DecimalFormat("#,###.##"); + + private static final String COMPACT = "%s/%s-%s/%s"; + private static final String EMPTY = ""; + private static final String SPACE = " "; + private static final String PER_SEC = "ps"; + private static final String FLOW = "flow"; + private static final String FLOWS = "flows"; + + // non-instantiable + private TopoUtils() { } + + /** + * Returns a compact identity for the given link, in the form + * used to identify links in the Topology View on the client. + * + * @param link link + * @return compact link identity + */ + public static String compactLinkString(Link link) { + return String.format(COMPACT, link.src().elementId(), link.src().port(), + link.dst().elementId(), link.dst().port()); + } + + /** + * Produces a canonical link key, that is, one that will match both a link + * and its inverse. + * + * @param link the link + * @return canonical key + */ + public static LinkKey canonicalLinkKey(Link link) { + String sn = link.src().elementId().toString(); + String dn = link.dst().elementId().toString(); + return sn.compareTo(dn) < 0 ? + linkKey(link.src(), link.dst()) : linkKey(link.dst(), link.src()); + } + + /** + * Returns human readable count of bytes, to be displayed as a label. + * + * @param bytes number of bytes + * @return formatted byte count + */ + public static String formatBytes(long bytes) { + String unit; + double value; + if (bytes > GIGA) { + value = bytes / GIGA; + unit = GBYTES_UNIT; + } else if (bytes > MEGA) { + value = bytes / MEGA; + unit = MBYTES_UNIT; + } else if (bytes > KILO) { + value = bytes / KILO; + unit = KBYTES_UNIT; + } else { + value = bytes; + unit = BYTES_UNIT; + } + return DF2.format(value) + SPACE + unit; + } + + /** + * Returns human readable bit rate, to be displayed as a label. + * + * @param bytes bytes per second + * @return formatted bits per second + */ + public static String formatBitRate(long bytes) { + String unit; + double value; + + //Convert to bits + long bits = bytes * 8; + if (bits > GIGA) { + value = bits / GIGA; + unit = GBITS_UNIT; + + // NOTE: temporary hack to clip rate at 10.0 Gbps + // Added for the CORD Fabric demo at ONS 2015 + // TODO: provide a more elegant solution to this issue + if (value > 10.0) { + value = 10.0; + } + + } else if (bits > MEGA) { + value = bits / MEGA; + unit = MBITS_UNIT; + } else if (bits > KILO) { + value = bits / KILO; + unit = KBITS_UNIT; + } else { + value = bits; + unit = BITS_UNIT; + } + return DF2.format(value) + SPACE + unit + PER_SEC; + } + + /** + * Returns human readable flow count, to be displayed as a label. + * + * @param flows number of flows + * @return formatted flow count + */ + public static String formatFlows(long flows) { + if (flows < 1) { + return EMPTY; + } + return String.valueOf(flows) + SPACE + (flows > 1 ? FLOWS : FLOW); + } +} diff --git a/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/package-info.java b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/package-info.java new file mode 100644 index 00000000..85ac7fea --- /dev/null +++ b/framework/src/onos/core/api/src/main/java/org/onosproject/ui/topo/package-info.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +/** + * Mechanism for dynamically extending topology view with information and + * behaviour overlays. + */ +package org.onosproject.ui.topo; \ No newline at end of file diff --git a/framework/src/onos/core/api/src/main/javadoc/org/onosproject/net/flow/doc-files/flow-design.png b/framework/src/onos/core/api/src/main/javadoc/org/onosproject/net/flow/doc-files/flow-design.png new file mode 100644 index 00000000..e08745d1 Binary files /dev/null and b/framework/src/onos/core/api/src/main/javadoc/org/onosproject/net/flow/doc-files/flow-design.png differ diff --git a/framework/src/onos/core/api/src/main/javadoc/org/onosproject/net/intent/doc-files/intent-design.png b/framework/src/onos/core/api/src/main/javadoc/org/onosproject/net/intent/doc-files/intent-design.png new file mode 100644 index 00000000..4392ad45 Binary files /dev/null and b/framework/src/onos/core/api/src/main/javadoc/org/onosproject/net/intent/doc-files/intent-design.png differ diff --git a/framework/src/onos/core/api/src/main/javadoc/org/onosproject/net/intent/doc-files/intent-states.png b/framework/src/onos/core/api/src/main/javadoc/org/onosproject/net/intent/doc-files/intent-states.png new file mode 100644 index 00000000..32804191 Binary files /dev/null and b/framework/src/onos/core/api/src/main/javadoc/org/onosproject/net/intent/doc-files/intent-states.png differ diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/TestApplicationId.java b/framework/src/onos/core/api/src/test/java/org/onosproject/TestApplicationId.java new file mode 100644 index 00000000..a57d5e8a --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/TestApplicationId.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014 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; + +import org.onosproject.core.ApplicationId; + +import java.util.Objects; + +/** + * Test application ID. + */ +public class TestApplicationId implements ApplicationId { + + private final String name; + private final short id; + + public TestApplicationId(String name) { + this.name = name; + this.id = (short) Objects.hash(name); + } + + public static ApplicationId create(String name) { + return new TestApplicationId(name); + } + + @Override + public short id() { + return id; + } + + @Override + public String name() { + return name; + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/VersionTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/VersionTest.java new file mode 100644 index 00000000..ecf5f34e --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/VersionTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 2014 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; + +import com.google.common.testing.EqualsTester; +import org.junit.Test; +import org.onosproject.core.Version; + +import static org.junit.Assert.*; +import static org.onosproject.core.Version.version; + +/** + * Tests of the version descriptor. + */ +public class VersionTest { + + @Test + public void fromParts() { + Version v = version(1, 2, "3", "4321"); + assertEquals("wrong major", 1, v.major()); + assertEquals("wrong minor", 2, v.minor()); + assertEquals("wrong patch", "3", v.patch()); + assertEquals("wrong build", "4321", v.build()); + } + + @Test + public void fromString() { + Version v = version("1.2.3.4321"); + assertEquals("wrong major", 1, v.major()); + assertEquals("wrong minor", 2, v.minor()); + assertEquals("wrong patch", "3", v.patch()); + assertEquals("wrong build", "4321", v.build()); + } + + @Test + public void snapshot() { + Version v = version("1.2.3-SNAPSHOT"); + assertEquals("wrong major", 1, v.major()); + assertEquals("wrong minor", 2, v.minor()); + assertEquals("wrong patch", "3", v.patch()); + assertEquals("wrong build", "SNAPSHOT", v.build()); + } + + @Test + public void shortNumber() { + Version v = version("1.2.3"); + assertEquals("wrong major", 1, v.major()); + assertEquals("wrong minor", 2, v.minor()); + assertEquals("wrong patch", "3", v.patch()); + assertEquals("wrong build", null, v.build()); + } + + @Test + public void minimal() { + Version v = version("1.4"); + assertEquals("wrong major", 1, v.major()); + assertEquals("wrong minor", 4, v.minor()); + assertEquals("wrong patch", null, v.patch()); + assertEquals("wrong build", null, v.build()); + } + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(version("1.2.3.4321"), version(1, 2, "3", "4321")) + .addEqualityGroup(version("1.9.3.4321"), version(1, 9, "3", "4321")) + .addEqualityGroup(version("1.2.8.4321"), version(1, 2, "8", "4321")) + .addEqualityGroup(version("1.2.3.x"), version(1, 2, "3", "x")) + .testEquals(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationAdminServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationAdminServiceAdapter.java new file mode 100644 index 00000000..edcc2094 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationAdminServiceAdapter.java @@ -0,0 +1,78 @@ +/* + * 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.app; + +import org.onosproject.core.Application; +import org.onosproject.core.ApplicationId; +import org.onosproject.security.Permission; + +import java.io.InputStream; +import java.util.Set; + +/** + * Adapter for testing against application admin service. + */ +public class ApplicationAdminServiceAdapter extends ApplicationServiceAdapter + implements ApplicationAdminService { + @Override + public Set getApplications() { + return null; + } + + @Override + public Application getApplication(ApplicationId appId) { + return null; + } + + @Override + public ApplicationState getState(ApplicationId appId) { + return null; + } + + @Override + public Set getPermissions(ApplicationId appId) { + return null; + } + + @Override + public void addListener(ApplicationListener listener) { + } + + @Override + public void removeListener(ApplicationListener listener) { + } + + @Override + public Application install(InputStream appDescStream) { + return null; + } + + @Override + public void uninstall(ApplicationId appId) { + } + + @Override + public void activate(ApplicationId appId) { + } + + @Override + public void deactivate(ApplicationId appId) { + } + + @Override + public void setPermissions(ApplicationId appId, Set permissions) { + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationEventTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationEventTest.java new file mode 100644 index 00000000..d31cc268 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationEventTest.java @@ -0,0 +1,55 @@ +/* + * 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.app; + +import org.junit.Test; +import org.onosproject.core.Application; +import org.onosproject.core.DefaultApplication; +import org.onosproject.event.AbstractEventTest; + +import java.util.Optional; + +import static org.onosproject.app.ApplicationEvent.Type.APP_ACTIVATED; +import static org.onosproject.app.DefaultApplicationDescriptionTest.*; +import static org.onosproject.core.DefaultApplicationTest.APP_ID; + +/** + * Test of the application event. + */ +public class ApplicationEventTest extends AbstractEventTest { + + private Application createApp() { + return new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, + PERMS, Optional.of(FURL), FEATURES); + } + + @Test + public void withoutTime() { + Application app = createApp(); + ApplicationEvent event = new ApplicationEvent(APP_ACTIVATED, app, 123L); + validateEvent(event, APP_ACTIVATED, app, 123L); + } + + @Test + public void withTime() { + Application app = createApp(); + long before = System.currentTimeMillis(); + ApplicationEvent event = new ApplicationEvent(APP_ACTIVATED, app); + long after = System.currentTimeMillis(); + validateEvent(event, APP_ACTIVATED, app, before, after); + } + +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationExceptionTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationExceptionTest.java new file mode 100644 index 00000000..a0c7ef1c --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationExceptionTest.java @@ -0,0 +1,36 @@ +/* + * 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.app; + +import org.onlab.junit.ExceptionTest; + +public class ApplicationExceptionTest extends ExceptionTest { + + @Override + protected Exception getDefault() { + return new ApplicationException(); + } + + @Override + protected Exception getWithMessage() { + return new ApplicationException(MESSAGE); + } + + @Override + protected Exception getWithMessageAndCause() { + return new ApplicationException(MESSAGE, CAUSE); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationServiceAdapter.java new file mode 100644 index 00000000..479cc59a --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationServiceAdapter.java @@ -0,0 +1,60 @@ +/* + * 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.app; + +import org.onosproject.core.Application; +import org.onosproject.core.ApplicationId; +import org.onosproject.security.Permission; + +import java.util.Set; + +/** + * Adapter for testing against application service. + */ +public class ApplicationServiceAdapter implements ApplicationService { + @Override + public Set getApplications() { + return null; + } + + @Override + public ApplicationId getId(String name) { + return null; + } + + @Override + public Application getApplication(ApplicationId appId) { + return null; + } + + @Override + public ApplicationState getState(ApplicationId appId) { + return null; + } + + @Override + public Set getPermissions(ApplicationId appId) { + return null; + } + + @Override + public void addListener(ApplicationListener listener) { + } + + @Override + public void removeListener(ApplicationListener listener) { + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationStoreAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationStoreAdapter.java new file mode 100644 index 00000000..1a9ad8d2 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/app/ApplicationStoreAdapter.java @@ -0,0 +1,78 @@ +/* + * 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.app; + +import org.onosproject.core.Application; +import org.onosproject.core.ApplicationId; +import org.onosproject.security.Permission; +import org.onosproject.store.AbstractStore; + +import java.io.InputStream; +import java.util.Set; + +/** + * Adapter for application testing against application store. + */ +public class ApplicationStoreAdapter + extends AbstractStore + implements ApplicationStore { + @Override + public Set getApplications() { + return null; + } + + @Override + public ApplicationId getId(String name) { + return null; + } + + @Override + public Application getApplication(ApplicationId appId) { + return null; + } + + @Override + public ApplicationState getState(ApplicationId appId) { + return null; + } + + @Override + public Application create(InputStream appDescStream) { + return null; + } + + @Override + public void remove(ApplicationId appId) { + } + + @Override + public void activate(ApplicationId appId) { + } + + @Override + public void deactivate(ApplicationId appId) { + } + + @Override + public Set getPermissions(ApplicationId appId) { + return null; + } + + @Override + public void setPermissions(ApplicationId appId, Set permissions) { + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/app/DefaultApplicationDescriptionTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/app/DefaultApplicationDescriptionTest.java new file mode 100644 index 00000000..d40d3fea --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/app/DefaultApplicationDescriptionTest.java @@ -0,0 +1,66 @@ +/* + * 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.app; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import org.junit.Test; +import org.onosproject.core.ApplicationRole; +import org.onosproject.core.Version; +import org.onosproject.security.AppPermission; +import org.onosproject.security.Permission; + +import java.net.URI; +import java.util.List; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + + +/** + * Basic tests of the default app description. + */ +public class DefaultApplicationDescriptionTest { + + public static final String APP_NAME = "org.foo.app"; + public static final Version VER = Version.version(1, 2, "a", null); + public static final String DESC = "Awesome application from Circus, Inc."; + public static final String ORIGIN = "Circus"; + public static final ApplicationRole ROLE = ApplicationRole.ADMIN; + public static final Set PERMS = ImmutableSet.of( + new Permission(AppPermission.class.getName(), "FLOWRULE_WRITE"), + new Permission(AppPermission.class.getName(), "FLOWRULE_READ")); + public static final URI FURL = URI.create("mvn:org.foo-features/1.2a/xml/features"); + public static final List FEATURES = ImmutableList.of("foo", "bar"); + + @Test + public void basics() { + ApplicationDescription app = + new DefaultApplicationDescription(APP_NAME, VER, DESC, ORIGIN, + ROLE, PERMS, FURL, FEATURES); + assertEquals("incorrect id", APP_NAME, app.name()); + assertEquals("incorrect version", VER, app.version()); + assertEquals("incorrect description", DESC, app.description()); + assertEquals("incorrect origin", ORIGIN, app.origin()); + assertEquals("incorect role", ROLE, app.role()); + assertEquals("incorrect permissions", PERMS, app.permissions()); + assertEquals("incorrect features repo", FURL, app.featuresRepo().get()); + assertEquals("incorrect features", FEATURES, app.features()); + assertTrue("incorrect toString", app.toString().contains(APP_NAME)); + } + +} \ No newline at end of file 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 new file mode 100644 index 00000000..a1abd188 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ComponentConfigAdapter.java @@ -0,0 +1,53 @@ +/* + * 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; + +import java.util.Set; + +/** + * Adapter for testing against component configuration service. + */ +public class ComponentConfigAdapter implements ComponentConfigService { + @Override + public Set getComponentNames() { + return null; + } + + @Override + public void registerProperties(Class componentClass) { + + } + + @Override + public void unregisterProperties(Class componentClass, boolean clear) { + + } + + @Override + public Set getProperties(String componentName) { + return null; + } + + @Override + public void setProperty(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/cfg/ConfigPropertyTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ConfigPropertyTest.java new file mode 100644 index 00000000..b4ba8634 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/cfg/ConfigPropertyTest.java @@ -0,0 +1,97 @@ +/* + * 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; + +import com.google.common.testing.EqualsTester; +import org.junit.Test; +import org.onosproject.cfg.ConfigProperty.Type; + +import static org.junit.Assert.*; +import static org.onosproject.cfg.ConfigProperty.Type.*; +import static org.onosproject.cfg.ConfigProperty.defineProperty; +import static org.onosproject.cfg.ConfigProperty.resetProperty; +import static org.onosproject.cfg.ConfigProperty.setProperty; + +/** + * Set of tests of the configuration property class. + */ +public class ConfigPropertyTest { + + @Test + public void basics() { + ConfigProperty p = defineProperty("foo", STRING, "bar", "Foo Prop"); + validate(p, "foo", STRING, "bar", "bar"); + p = setProperty(p, "BAR"); + validate(p, "foo", STRING, "BAR", "bar"); + p = resetProperty(p); + validate(p, "foo", STRING, "bar", "bar"); + } + + @Test + public void equality() { + new EqualsTester() + .addEqualityGroup(defineProperty("foo", STRING, "bar", "Desc"), + defineProperty("foo", STRING, "goo", "Desc")) + .addEqualityGroup(defineProperty("bar", STRING, "bar", "Desc"), + defineProperty("bar", STRING, "goo", "Desc")) + .testEquals(); + } + + private void validate(ConfigProperty p, String name, Type type, String v, String dv) { + assertEquals("incorrect name", name, p.name()); + assertEquals("incorrect type", type, p.type()); + assertEquals("incorrect value", v, p.value()); + assertEquals("incorrect default", dv, p.defaultValue()); + assertEquals("incorrect description", "Foo Prop", p.description()); + } + + @Test + public void asInteger() { + ConfigProperty p = defineProperty("foo", INTEGER, "123", "Foo Prop"); + validate(p, "foo", INTEGER, "123", "123"); + assertEquals("incorrect value", 123, p.asInteger()); + assertEquals("incorrect value", 123L, p.asLong()); + } + + @Test + public void asLong() { + ConfigProperty p = defineProperty("foo", LONG, "123", "Foo Prop"); + validate(p, "foo", LONG, "123", "123"); + assertEquals("incorrect value", 123L, p.asLong()); + } + + @Test + public void asFloat() { + ConfigProperty p = defineProperty("foo", FLOAT, "123.0", "Foo Prop"); + validate(p, "foo", FLOAT, "123.0", "123.0"); + assertEquals("incorrect value", 123.0, p.asFloat(), 0.01); + assertEquals("incorrect value", 123.0, p.asDouble(), 0.01); + } + + @Test + public void asDouble() { + ConfigProperty p = defineProperty("foo", DOUBLE, "123.0", "Foo Prop"); + validate(p, "foo", DOUBLE, "123.0", "123.0"); + assertEquals("incorrect value", 123.0, p.asDouble(), 0.01); + } + + @Test + public void asBoolean() { + ConfigProperty p = defineProperty("foo", BOOLEAN, "true", "Foo Prop"); + validate(p, "foo", BOOLEAN, "true", "true"); + assertEquals("incorrect value", true, p.asBoolean()); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/ClusterServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/ClusterServiceAdapter.java new file mode 100644 index 00000000..b88b5ff6 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/ClusterServiceAdapter.java @@ -0,0 +1,64 @@ +/* + * Copyright 2014-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.cluster; + +import java.util.Set; + +import org.joda.time.DateTime; +import org.onlab.packet.IpAddress; + +import com.google.common.collect.ImmutableSet; + +/** + * Test adapter for the cluster service. + */ +public class ClusterServiceAdapter implements ClusterService { + ControllerNode local = new DefaultControllerNode(new NodeId("local"), + IpAddress.valueOf("127.0.0.1")); + + @Override + public ControllerNode getLocalNode() { + return local; + } + + @Override + public Set getNodes() { + return ImmutableSet.of(local); + } + + @Override + public ControllerNode getNode(NodeId nodeId) { + return null; + } + + @Override + public ControllerNode.State getState(NodeId nodeId) { + return null; + } + + @Override + public DateTime getLastUpdated(NodeId nodeId) { + return null; + } + + @Override + public void addListener(ClusterEventListener listener) { + } + + @Override + public void removeListener(ClusterEventListener listener) { + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/ControllerNodeToNodeIdTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/ControllerNodeToNodeIdTest.java new file mode 100644 index 00000000..0b4d1ef6 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/ControllerNodeToNodeIdTest.java @@ -0,0 +1,59 @@ +/* + * Copyright 2014 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.cluster; + +import static com.google.common.base.Predicates.notNull; +import static org.junit.Assert.*; +import static org.onosproject.cluster.ControllerNodeToNodeId.toNodeId; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; +import org.onlab.packet.IpAddress; + +import com.google.common.collect.FluentIterable; + + +public class ControllerNodeToNodeIdTest { + + private static final NodeId NID1 = new NodeId("foo"); + private static final NodeId NID2 = new NodeId("bar"); + private static final NodeId NID3 = new NodeId("buz"); + + private static final IpAddress IP1 = IpAddress.valueOf("127.0.0.1"); + private static final IpAddress IP2 = IpAddress.valueOf("127.0.0.2"); + private static final IpAddress IP3 = IpAddress.valueOf("127.0.0.3"); + + private static final ControllerNode CN1 = new DefaultControllerNode(NID1, IP1); + private static final ControllerNode CN2 = new DefaultControllerNode(NID2, IP2); + private static final ControllerNode CN3 = new DefaultControllerNode(NID3, IP3); + + + @Test + public final void testToNodeId() { + + final Iterable nodes = Arrays.asList(CN1, CN2, CN3, null); + final List nodeIds = Arrays.asList(NID1, NID2, NID3); + + assertEquals(nodeIds, + FluentIterable.from(nodes) + .transform(toNodeId()) + .filter(notNull()) + .toList()); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/LeadershipEventTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/LeadershipEventTest.java new file mode 100644 index 00000000..be0321bf --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/LeadershipEventTest.java @@ -0,0 +1,76 @@ +/* + * 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.cluster; + +import org.junit.Test; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +/** + * Unit tests for the leadership event test. + */ +public class LeadershipEventTest { + private final NodeId node1 = new NodeId("1"); + private final NodeId node2 = new NodeId("2"); + private final Leadership lead1 = new Leadership("topic1", node1, 1L, 2L); + private final Leadership lead2 = new Leadership("topic1", node2, 1L, 2L); + private final LeadershipEvent event1 = + new LeadershipEvent(LeadershipEvent.Type.LEADER_ELECTED, lead1); + private final long time = System.currentTimeMillis(); + private final LeadershipEvent event2 = + new LeadershipEvent(LeadershipEvent.Type.CANDIDATES_CHANGED, + lead2, time); + private final LeadershipEvent sameAsEvent2 = + new LeadershipEvent(LeadershipEvent.Type.CANDIDATES_CHANGED, + lead2, time); + private final LeadershipEvent event3 = + new LeadershipEvent(LeadershipEvent.Type.LEADER_BOOTED, lead1); + private final LeadershipEvent event4 = + new LeadershipEvent(LeadershipEvent.Type.LEADER_REELECTED, lead1); + private final LeadershipEvent event5 = + new LeadershipEvent(LeadershipEvent.Type.LEADER_REELECTED, lead2); + + /** + * Tests for proper operation of equals(), hashCode() and toString() methods. + */ + @Test + public void checkEquals() { + new EqualsTester() + .addEqualityGroup(event1) + .addEqualityGroup(event2, sameAsEvent2) + .addEqualityGroup(event3) + .addEqualityGroup(event4) + .addEqualityGroup(event5) + .testEquals(); + } + + /** + * Tests that objects are created properly. + */ + @Test + public void checkConstruction() { + assertThat(event1.type(), is(LeadershipEvent.Type.LEADER_ELECTED)); + assertThat(event1.subject(), is(lead1)); + + assertThat(event2.time(), is(time)); + assertThat(event2.type(), is(LeadershipEvent.Type.CANDIDATES_CHANGED)); + assertThat(event2.subject(), is(lead2)); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/LeadershipServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/LeadershipServiceAdapter.java new file mode 100644 index 00000000..e1d421d0 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/LeadershipServiceAdapter.java @@ -0,0 +1,87 @@ +/* + * 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.cluster; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; + +/** + * Test adapter for leadership service. + */ +public class LeadershipServiceAdapter implements LeadershipService { + + @Override + public NodeId getLeader(String path) { + return null; + } + + @Override + public Leadership getLeadership(String path) { + return null; + } + + @Override + public Set ownedTopics(NodeId nodeId) { + return null; + } + + @Override + public CompletableFuture runForLeadership(String path) { + return null; + } + + @Override + public CompletableFuture withdraw(String path) { + return null; + } + + @Override + public Map getLeaderBoard() { + return null; + } + + @Override + public void addListener(LeadershipEventListener listener) { + + } + + @Override + public void removeListener(LeadershipEventListener listener) { + + } + + @Override + public Map> getCandidates() { + return null; + } + + @Override + public List getCandidates(String path) { + return null; + } + + @Override + public boolean stepdown(String path) { + return false; + } + + @Override + public boolean makeTopCandidate(String path, NodeId nodeId) { + return false; + } +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/LeadershipTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/LeadershipTest.java new file mode 100644 index 00000000..e2a86587 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/LeadershipTest.java @@ -0,0 +1,75 @@ +/* + * 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.cluster; + +import org.junit.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +/** + * Unit tests for the Leadership class. + */ +public class LeadershipTest { + private final NodeId node1 = new NodeId("1"); + private final NodeId node2 = new NodeId("2"); + private final Leadership lead1 = new Leadership("topic1", node1, 1L, 2L); + private final Leadership sameAsLead1 = new Leadership("topic1", node1, 1L, 2L); + private final Leadership lead2 = new Leadership("topic2", node1, 1L, 2L); + private final Leadership lead3 = new Leadership("topic1", node1, 2L, 2L); + private final Leadership lead4 = new Leadership("topic1", node1, 3L, 2L); + private final Leadership lead5 = new Leadership("topic1", node1, 3L, 3L); + private final Leadership lead6 = new Leadership("topic1", node1, + ImmutableList.of(node2), 1L, 2L); + private final Leadership lead7 = new Leadership("topic1", + ImmutableList.of(node2), 1L, 2L); + + /** + * Tests for proper operation of equals(), hashCode() and toString() methods. + */ + @Test + public void checkEquals() { + new EqualsTester() + .addEqualityGroup(lead1, sameAsLead1) + .addEqualityGroup(lead2) + .addEqualityGroup(lead3) + .addEqualityGroup(lead4) + .addEqualityGroup(lead5) + .addEqualityGroup(lead6) + .addEqualityGroup(lead7) + .testEquals(); + } + + /** + * Tests that objects are created properly and accessor methods return + * the correct vsalues. + */ + @Test + public void checkConstruction() { + assertThat(lead6.electedTime(), is(2L)); + assertThat(lead6.epoch(), is(1L)); + assertThat(lead6.leader(), is(node1)); + assertThat(lead6.topic(), is("topic1")); + assertThat(lead6.candidates(), hasSize(1)); + assertThat(lead6.candidates(), contains(node2)); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/RoleInfoTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/RoleInfoTest.java new file mode 100644 index 00000000..4998bf5a --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/cluster/RoleInfoTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 2014-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.cluster; + +import java.util.List; + +import org.junit.Test; + +import com.google.common.collect.Lists; +import com.google.common.testing.EqualsTester; + +import static org.junit.Assert.assertEquals; + +/** + * Test to check behavioral correctness of the RoleInfo structure. + */ +public class RoleInfoTest { + private static final NodeId N1 = new NodeId("n1"); + private static final NodeId N2 = new NodeId("n2"); + private static final NodeId N3 = new NodeId("n3"); + private static final NodeId N4 = new NodeId("n4"); + + private static final List BKUP1 = Lists.newArrayList(N2, N3); + private static final List BKUP2 = Lists.newArrayList(N3, N4); + + private static final RoleInfo RI1 = new RoleInfo(N1, BKUP1); + private static final RoleInfo RI2 = new RoleInfo(N1, BKUP2); + private static final RoleInfo RI3 = new RoleInfo(N2, BKUP1); + private static final RoleInfo RI4 = new RoleInfo(null, BKUP2); + + @Test + public void testEquality() { + new EqualsTester() + .addEqualityGroup(RI1, new RoleInfo(new NodeId("n1"), Lists.newArrayList(N2, N3))) + .addEqualityGroup(RI3); + } + + @Test + public void basics() { + assertEquals("wrong master", new NodeId("n1"), RI1.master()); + assertEquals("wrong Backups", RI1.backups(), Lists.newArrayList(N2, N3)); + assertEquals("wrong empty master", RI4.master(), null); + + List bkup3 = Lists.newArrayList(N3, new NodeId("n4")); + assertEquals("equals() broken", new RoleInfo(N1, bkup3), RI2); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/codec/JsonCodecTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/codec/JsonCodecTest.java new file mode 100644 index 00000000..eb04d9a5 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/codec/JsonCodecTest.java @@ -0,0 +1,99 @@ +/* + * Copyright 2014 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; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.ImmutableList; +import org.junit.Test; + +import java.util.List; +import java.util.Objects; + +import static org.junit.Assert.assertEquals; + +/** + * Test of the base JSON codec abstraction. + */ +public class JsonCodecTest { + + private static class Foo { + final String name; + + Foo(String name) { + this.name = name; + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final Foo other = (Foo) obj; + return Objects.equals(this.name, other.name); + } + } + + private static class FooCodec extends JsonCodec { + @Override + public ObjectNode encode(Foo entity, CodecContext context) { + return context.mapper().createObjectNode().put("name", entity.name); + } + + @Override + public Foo decode(ObjectNode json, CodecContext context) { + return new Foo(json.get("name").asText()); + } + } + + @Test + public void encode() { + Foo f1 = new Foo("foo"); + Foo f2 = new Foo("bar"); + FooCodec codec = new FooCodec(); + ImmutableList entities = ImmutableList.of(f1, f2); + ArrayNode json = codec.encode(entities, new TestContext()); + List foos = codec.decode(json, new TestContext()); + assertEquals("incorrect encode/decode", entities, foos); + } + + private class TestContext implements CodecContext { + private ObjectMapper mapper = new ObjectMapper(); + @Override + public ObjectMapper mapper() { + return mapper; + } + + @Override + public JsonCodec codec(Class entityClass) { + return null; + } + + @Override + public T getService(Class serviceClass) { + return null; + } + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/core/ApplicationIdStoreAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/core/ApplicationIdStoreAdapter.java new file mode 100644 index 00000000..c3d0f237 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/core/ApplicationIdStoreAdapter.java @@ -0,0 +1,43 @@ +/* + * 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.core; + +import java.util.Set; + +/** + * Adapter for testing against app id store. + */ +public class ApplicationIdStoreAdapter implements ApplicationIdStore { + @Override + public Set getAppIds() { + return null; + } + + @Override + public ApplicationId getAppId(Short id) { + return null; + } + + @Override + public ApplicationId getAppId(String name) { + return null; + } + + @Override + public ApplicationId registerApplication(String identifier) { + return null; + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/core/CoreServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/core/CoreServiceAdapter.java new file mode 100644 index 00000000..0f6abd68 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/core/CoreServiceAdapter.java @@ -0,0 +1,54 @@ +/* + * 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.core; + +import java.util.Set; + +/** + * Test adapter for core service. + */ +public class CoreServiceAdapter implements CoreService { + @Override + public Version version() { + return null; + } + + @Override + public Set getAppIds() { + return null; + } + + @Override + public ApplicationId getAppId(Short id) { + return null; + } + + @Override + public ApplicationId getAppId(String name) { + return null; + } + + @Override + public ApplicationId registerApplication(String identifier) { + return null; + } + + @Override + public IdGenerator getIdGenerator(String topic) { + return null; + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/core/DefaultApplicationTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/core/DefaultApplicationTest.java new file mode 100644 index 00000000..cbedb79c --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/core/DefaultApplicationTest.java @@ -0,0 +1,63 @@ +/* + * 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.core; + +import com.google.common.testing.EqualsTester; +import org.junit.Test; + +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.onosproject.app.DefaultApplicationDescriptionTest.*; + +/** + * Basic tests of the default app descriptor. + */ +public class DefaultApplicationTest { + + public static final ApplicationId APP_ID = new DefaultApplicationId(2, APP_NAME); + + @Test + public void basics() { + Application app = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, + PERMS, Optional.of(FURL), FEATURES); + assertEquals("incorrect id", APP_ID, app.id()); + assertEquals("incorrect version", VER, app.version()); + assertEquals("incorrect description", DESC, app.description()); + assertEquals("incorrect origin", ORIGIN, app.origin()); + assertEquals("incorrect role", ROLE, app.role()); + assertEquals("incorrect permissions", PERMS, app.permissions()); + assertEquals("incorrect features repo", FURL, app.featuresRepo().get()); + assertEquals("incorrect features", FEATURES, app.features()); + assertTrue("incorrect toString", app.toString().contains(APP_NAME)); + } + + @Test + public void testEquality() { + Application a1 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, + PERMS, Optional.of(FURL), FEATURES); + Application a2 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, + PERMS, Optional.of(FURL), FEATURES); + Application a3 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, + PERMS, Optional.empty(), FEATURES); + Application a4 = new DefaultApplication(APP_ID, VER, DESC, ORIGIN + "asd", ROLE, + PERMS, Optional.of(FURL), FEATURES); + new EqualsTester().addEqualityGroup(a1, a2) + .addEqualityGroup(a3).addEqualityGroup(a4).testEquals(); + } + +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/core/DefaultGroupIdTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/core/DefaultGroupIdTest.java new file mode 100644 index 00000000..21dea86b --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/core/DefaultGroupIdTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014 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.core; + +import com.google.common.testing.EqualsTester; +import org.junit.Test; + +/** + * Test for DefaultGroupId. + */ +public class DefaultGroupIdTest { + + /** + * Tests the equality of the instances. + */ + @Test + public void testEquality() { + DefaultGroupId id1 = new DefaultGroupId((short) 1); + DefaultGroupId id2 = new DefaultGroupId((short) 1); + DefaultGroupId id3 = new DefaultGroupId((short) 2); + + new EqualsTester() + .addEqualityGroup(id1, id2) + .addEqualityGroup(id3) + .testEquals(); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/core/UnavailableIdExceptionTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/core/UnavailableIdExceptionTest.java new file mode 100644 index 00000000..ac565d80 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/core/UnavailableIdExceptionTest.java @@ -0,0 +1,36 @@ +/* + * 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.core; + +import org.onlab.junit.ExceptionTest; + +public class UnavailableIdExceptionTest extends ExceptionTest { + + @Override + protected Exception getDefault() { + return new UnavailableIdException(); + } + + @Override + protected Exception getWithMessage() { + return new UnavailableIdException(MESSAGE); + } + + @Override + protected Exception getWithMessageAndCause() { + return new UnavailableIdException(MESSAGE, CAUSE); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/event/AbstractEventTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/event/AbstractEventTest.java new file mode 100644 index 00000000..c66c4b84 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/event/AbstractEventTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2014 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.event; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.onosproject.event.TestEvent.Type.FOO; + +/** + * Tests of the base event abstraction. + */ +public class AbstractEventTest { + + /** + * Validates the base attributes of an event. + * + * @param event event to validate + * @param type event type + * @param subject event subject + * @param time event time + * @param type of event + * @param type of subject + */ + protected static + void validateEvent(Event event, T type, S subject, long time) { + assertEquals("incorrect type", type, event.type()); + assertEquals("incorrect subject", subject, event.subject()); + assertEquals("incorrect time", time, event.time()); + } + + /** + * Validates the base attributes of an event. + * + * @param event event to validate + * @param type event type + * @param subject event subject + * @param minTime minimum event time inclusive + * @param maxTime maximum event time inclusive + * @param type of event + * @param type of subject + */ + protected static + void validateEvent(Event event, T type, S subject, + long minTime, long maxTime) { + assertEquals("incorrect type", type, event.type()); + assertEquals("incorrect subject", subject, event.subject()); + assertTrue("incorrect time", minTime <= event.time() && event.time() <= maxTime); + } + + @Test + public void withTime() { + TestEvent event = new TestEvent(FOO, "foo", 123L); + validateEvent(event, FOO, "foo", 123L); + } + + @Test + public void withoutTime() { + long before = System.currentTimeMillis(); + TestEvent event = new TestEvent(FOO, "foo"); + long after = System.currentTimeMillis(); + validateEvent(event, FOO, "foo", before, after); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/event/BrokenListener.java b/framework/src/onos/core/api/src/test/java/org/onosproject/event/BrokenListener.java new file mode 100644 index 00000000..1a013ada --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/event/BrokenListener.java @@ -0,0 +1,28 @@ +/* + * Copyright 2014 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.event; + +/** + * Test event listener fixture. + */ +public class BrokenListener extends TestListener { + + public void event(TestEvent event) { + throw new IllegalStateException("boom"); + } + +} + diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/event/DefaultEventSinkRegistryTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/event/DefaultEventSinkRegistryTest.java new file mode 100644 index 00000000..2e24228a --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/event/DefaultEventSinkRegistryTest.java @@ -0,0 +1,71 @@ +/* + * Copyright 2014 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.event; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Tests of the default event sink registry. + */ +public class DefaultEventSinkRegistryTest { + + private DefaultEventSinkRegistry registry; + + private static class FooEvent extends TestEvent { + public FooEvent(String subject) { + super(Type.FOO, subject); + } + } + + private static class BarEvent extends TestEvent { + public BarEvent(String subject) { + super(Type.BAR, subject); + } + } + + private static class FooSink implements EventSink { + @Override public void process(FooEvent event) {} + } + + private static class BarSink implements EventSink { + @Override public void process(BarEvent event) {} + } + + @Before + public void setUp() { + registry = new DefaultEventSinkRegistry(); + } + + @Test + public void basics() { + FooSink fooSink = new FooSink(); + BarSink barSink = new BarSink(); + registry.addSink(FooEvent.class, fooSink); + registry.addSink(BarEvent.class, barSink); + + assertEquals("incorrect sink count", 2, registry.getSinks().size()); + assertEquals("incorrect sink", fooSink, registry.getSink(FooEvent.class)); + assertEquals("incorrect sink", barSink, registry.getSink(BarEvent.class)); + + registry.removeSink(FooEvent.class); + assertNull("incorrect sink", registry.getSink(FooEvent.class)); + assertEquals("incorrect sink", barSink, registry.getSink(BarEvent.class)); + + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/event/EventDeliveryServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/event/EventDeliveryServiceAdapter.java new file mode 100644 index 00000000..6d5e8934 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/event/EventDeliveryServiceAdapter.java @@ -0,0 +1,60 @@ +/* + * 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.event; + +import java.util.Set; + +import static org.junit.Assert.*; + +/** + * Testing adapter for the event delivery service. + */ +public class EventDeliveryServiceAdapter implements EventDeliveryService { + @Override + public void setDispatchTimeLimit(long millis) { + + } + + @Override + public long getDispatchTimeLimit() { + return 0; + } + + @Override + public void post(Event event) { + + } + + @Override + public void addSink(Class eventClass, EventSink sink) { + + } + + @Override + public void removeSink(Class eventClass) { + + } + + @Override + public EventSink getSink(Class eventClass) { + return null; + } + + @Override + public Set> getSinks() { + return null; + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/event/ListenerRegistryTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/event/ListenerRegistryTest.java new file mode 100644 index 00000000..8cce6417 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/event/ListenerRegistryTest.java @@ -0,0 +1,74 @@ +/* + * Copyright 2014 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.event; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Unit tests for {@link ListenerRegistry}. + */ +public class ListenerRegistryTest { + + private static final TestEvent FOO_EVENT = + new TestEvent(TestEvent.Type.FOO, "foo"); + private static final TestEvent BAR_EVENT = + new TestEvent(TestEvent.Type.BAR, "bar"); + + private TestListener listener; + private TestListener secondListener; + private TestListenerRegistry manager; + + @Before + public void setUp() { + listener = new TestListener(); + secondListener = new TestListener(); + manager = new TestListenerRegistry(); + } + + @Test + public void basics() { + manager.addListener(listener); + manager.addListener(secondListener); + + manager.process(BAR_EVENT); + assertTrue("BAR not processed", listener.events.contains(BAR_EVENT)); + assertTrue("BAR not processed", secondListener.events.contains(BAR_EVENT)); + + manager.removeListener(listener); + + manager.process(FOO_EVENT); + assertFalse("FOO processed", listener.events.contains(FOO_EVENT)); + assertTrue("FOO not processed", secondListener.events.contains(FOO_EVENT)); + } + + @Test + public void badListener() { + listener = new BrokenListener(); + + manager.addListener(listener); + manager.addListener(secondListener); + + manager.process(BAR_EVENT); + assertFalse("BAR processed", listener.events.contains(BAR_EVENT)); + assertFalse("error not reported", manager.errors.isEmpty()); + assertTrue("BAR not processed", secondListener.events.contains(BAR_EVENT)); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/event/TestEvent.java b/framework/src/onos/core/api/src/test/java/org/onosproject/event/TestEvent.java new file mode 100644 index 00000000..8a507151 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/event/TestEvent.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014 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.event; + +/** + * Test event fixture. + */ +public class TestEvent extends AbstractEvent { + + public enum Type { FOO, BAR } + + public TestEvent(Type type, String subject) { + super(type, subject); + } + + public TestEvent(Type type, String subject, long timestamp) { + super(type, subject, timestamp); + } + +} + diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/event/TestListener.java b/framework/src/onos/core/api/src/test/java/org/onosproject/event/TestListener.java new file mode 100644 index 00000000..213f8c59 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/event/TestListener.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014 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.event; + +import java.util.ArrayList; +import java.util.List; + +/** + * Test event listener fixture. + */ +public class TestListener implements EventListener { + + public final List events = new ArrayList<>(); + + @Override + public void event(TestEvent event) { + events.add(event); + } + +} + diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/event/TestListenerRegistry.java b/framework/src/onos/core/api/src/test/java/org/onosproject/event/TestListenerRegistry.java new file mode 100644 index 00000000..fd9b6d08 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/event/TestListenerRegistry.java @@ -0,0 +1,36 @@ +/* + * Copyright 2014 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.event; + +import java.util.ArrayList; +import java.util.List; + +/** + * Test event listener manager fixture. + */ +public class TestListenerRegistry + extends ListenerRegistry { + + public final List errors = new ArrayList<>(); + + @Override + protected void reportProblem(TestEvent event, Throwable error) { + super.reportProblem(event, error); + errors.add(error); + } + +} + diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/mastership/MastershipServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/mastership/MastershipServiceAdapter.java new file mode 100644 index 00000000..7db9b38b --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/mastership/MastershipServiceAdapter.java @@ -0,0 +1,67 @@ +/* + * Copyright 2014 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.mastership; + +import org.onosproject.cluster.NodeId; +import org.onosproject.cluster.RoleInfo; +import org.onosproject.net.DeviceId; +import org.onosproject.net.MastershipRole; + +import java.util.Set; +import java.util.concurrent.CompletableFuture; + +/** + * Test adapter for mastership service. + */ +public class MastershipServiceAdapter implements MastershipService { + @Override + public MastershipRole getLocalRole(DeviceId deviceId) { + return null; + } + + @Override + public CompletableFuture requestRoleFor(DeviceId deviceId) { + return null; + } + + @Override + public CompletableFuture relinquishMastership(DeviceId deviceId) { + return null; + } + + @Override + public NodeId getMasterFor(DeviceId deviceId) { + return null; + } + + @Override + public Set getDevicesOf(NodeId nodeId) { + return null; + } + + @Override + public void addListener(MastershipListener listener) { + } + + @Override + public void removeListener(MastershipListener listener) { + } + + @Override + public RoleInfo getNodesFor(DeviceId deviceId) { + return null; + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/mastership/MastershipTermTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/mastership/MastershipTermTest.java new file mode 100644 index 00000000..0ca9436b --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/mastership/MastershipTermTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014 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.mastership; + +import static org.junit.Assert.assertEquals; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; +import org.onosproject.cluster.NodeId; + +import com.google.common.testing.EqualsTester; + +public class MastershipTermTest { + + private static final NodeId N1 = new NodeId("foo"); + private static final NodeId N2 = new NodeId("bar"); + + private static final MastershipTerm TERM1 = MastershipTerm.of(N1, 0); + private static final MastershipTerm TERM2 = MastershipTerm.of(N2, 1); + private static final MastershipTerm TERM3 = MastershipTerm.of(N2, 1); + private static final MastershipTerm TERM4 = MastershipTerm.of(N1, 1); + + @Test + public void basics() { + assertEquals("incorrect term number", 0, TERM1.termNumber()); + assertEquals("incorrect master", new NodeId("foo"), TERM1.master()); + } + + @Test + public void testEquality() { + new EqualsTester().addEqualityGroup(MastershipTerm.of(N1, 0), TERM1) + .addEqualityGroup(TERM2, TERM3) + .addEqualityGroup(TERM4) + .testEquals(); + } + + /** + * Checks that the MembershipTerm class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(MastershipTerm.class); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/ConnectPointTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/ConnectPointTest.java new file mode 100644 index 00000000..2aecabd4 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/ConnectPointTest.java @@ -0,0 +1,110 @@ +/* + * Copyright 2014 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 com.google.common.testing.EqualsTester; +import org.junit.Test; + +import static junit.framework.TestCase.fail; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Test of the connection point entity. + */ +public class ConnectPointTest { + + private static final DeviceId DID1 = deviceId("1"); + private static final DeviceId DID2 = deviceId("2"); + private static final PortNumber P1 = portNumber(1); + private static final PortNumber P2 = portNumber(2); + + @Test + public void basics() { + ConnectPoint p = new ConnectPoint(DID1, P2); + assertEquals("incorrect element id", DID1, p.deviceId()); + assertEquals("incorrect element id", P2, p.port()); + } + + @Test + public void testEquality() { + new EqualsTester() + .addEqualityGroup(new ConnectPoint(DID1, P1), new ConnectPoint(DID1, P1)) + .addEqualityGroup(new ConnectPoint(DID1, P2), new ConnectPoint(DID1, P2)) + .addEqualityGroup(new ConnectPoint(DID2, P1), new ConnectPoint(DID2, P1)) + .testEquals(); + } + + @Test + public void testParseDeviceConnectPoint() { + String cp = "of:0011223344556677/1"; + + ConnectPoint connectPoint = ConnectPoint.deviceConnectPoint(cp); + assertEquals("of:0011223344556677", connectPoint.deviceId().toString()); + assertEquals("1", connectPoint.port().toString()); + + expectDeviceParseException(""); + expectDeviceParseException("1/"); + expectDeviceParseException("1/1/1"); + expectDeviceParseException("of:0011223344556677/word"); + } + + /** + * Parse a device connect point and expect an exception to be thrown. + * + * @param string string to parse + */ + private static void expectDeviceParseException(String string) { + try { + ConnectPoint.deviceConnectPoint(string); + fail("Expected exception was not thrown"); + } catch (Exception e) { + assertTrue(true); + } + } + + @Test + public void testParseHostConnectPoint() { + String cp = "16:3A:BD:6E:31:E4/-1/1"; + + ConnectPoint connectPoint = ConnectPoint.hostConnectPoint(cp); + assertEquals("16:3A:BD:6E:31:E4/-1", connectPoint.hostId().toString()); + assertEquals("1", connectPoint.port().toString()); + + expectHostParseException(""); + expectHostParseException("1/"); + expectHostParseException("1/1"); + expectHostParseException("1/1/1/1"); + expectHostParseException("16:3A:BD:6E:31:E4/word/1"); + expectHostParseException("16:3A:BD:6E:31:E4/1/word"); + } + + /** + * Parse a host connect point and expect an exception to be thrown. + * + * @param string string to parse + */ + private static void expectHostParseException(String string) { + try { + ConnectPoint.hostConnectPoint(string); + fail("Expected exception was not thrown"); + } catch (Exception e) { + assertTrue(true); + } + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultAnnotationsTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultAnnotationsTest.java new file mode 100644 index 00000000..1bac285d --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultAnnotationsTest.java @@ -0,0 +1,100 @@ +/* + * Copyright 2014 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.junit.Test; + +import static com.google.common.collect.ImmutableSet.of; +import static org.junit.Assert.*; +import static org.onosproject.net.DefaultAnnotations.builder; + +/** + * Tests of the default annotations. + */ +public class DefaultAnnotationsTest { + + private DefaultAnnotations annotations; + + @Test + public void basics() { + annotations = builder().set("foo", "1").set("bar", "2").build(); + assertEquals("incorrect keys", of("foo", "bar"), annotations.keys()); + assertEquals("incorrect value", "1", annotations.value("foo")); + assertEquals("incorrect value", "2", annotations.value("bar")); + } + + @Test + public void empty() { + annotations = builder().build(); + assertTrue("incorrect keys", annotations.keys().isEmpty()); + } + + @Test + public void remove() { + annotations = builder().remove("foo").set("bar", "2").build(); + assertEquals("incorrect keys", of("foo", "bar"), annotations.keys()); + assertNull("incorrect value", annotations.value("foo")); + assertEquals("incorrect value", "2", annotations.value("bar")); + } + + @Test + public void union() { + annotations = builder().set("foo", "1").set("bar", "2").remove("buz").build(); + assertEquals("incorrect keys", of("foo", "bar", "buz"), annotations.keys()); + + SparseAnnotations updates = builder().remove("foo").set("bar", "3").set("goo", "4").remove("fuzz").build(); + + SparseAnnotations result = DefaultAnnotations.union(annotations, updates); + + assertTrue("remove instruction in original remains", result.isRemoved("buz")); + assertTrue("remove instruction in update remains", result.isRemoved("fuzz")); + assertEquals("incorrect keys", of("buz", "goo", "bar", "fuzz"), result.keys()); + assertNull("incorrect value", result.value("foo")); + assertEquals("incorrect value", "3", result.value("bar")); + assertEquals("incorrect value", "4", result.value("goo")); + } + + @Test + public void merge() { + annotations = builder().set("foo", "1").set("bar", "2").build(); + assertEquals("incorrect keys", of("foo", "bar"), annotations.keys()); + + SparseAnnotations updates = builder().remove("foo").set("bar", "3").set("goo", "4").build(); + + annotations = DefaultAnnotations.merge(annotations, updates); + assertEquals("incorrect keys", of("goo", "bar"), annotations.keys()); + assertNull("incorrect value", annotations.value("foo")); + assertEquals("incorrect value", "3", annotations.value("bar")); + } + + @Test + public void noopMerge() { + annotations = builder().set("foo", "1").set("bar", "2").build(); + assertEquals("incorrect keys", of("foo", "bar"), annotations.keys()); + + SparseAnnotations updates = builder().build(); + assertSame("same annotations expected", annotations, + DefaultAnnotations.merge(annotations, updates)); + assertSame("same annotations expected", annotations, + DefaultAnnotations.merge(annotations, null)); + } + + @Test(expected = NullPointerException.class) + public void badMerge() { + DefaultAnnotations.merge(null, null); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultDeviceTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultDeviceTest.java new file mode 100644 index 00000000..1b0319a5 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultDeviceTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2014 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 com.google.common.testing.EqualsTester; +import org.junit.Test; +import org.onosproject.net.provider.ProviderId; +import org.onlab.packet.ChassisId; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.net.Device.Type.SWITCH; +import static org.onosproject.net.DeviceId.deviceId; + +/** + * Test of the default device model entity. + */ +public class DefaultDeviceTest { + + static final ProviderId PID = new ProviderId("of", "foo"); + static final DeviceId DID1 = deviceId("of:foo"); + static final DeviceId DID2 = deviceId("of:bar"); + static final String MFR = "whitebox"; + static final String HW = "1.1.x"; + static final String SW = "3.9.1"; + static final String SN1 = "43311-12345"; + static final String SN2 = "42346-43512"; + static final ChassisId CID = new ChassisId(); + + @Test + public void testEquality() { + Device d1 = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1, CID); + Device d2 = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1, CID); + Device d3 = new DefaultDevice(PID, DID2, SWITCH, MFR, HW, SW, SN2, CID); + Device d4 = new DefaultDevice(PID, DID2, SWITCH, MFR, HW, SW, SN2, CID); + Device d5 = new DefaultDevice(PID, DID2, SWITCH, MFR, HW, SW, SN1, CID); + + new EqualsTester().addEqualityGroup(d1, d2) + .addEqualityGroup(d3, d4) + .addEqualityGroup(d5) + .testEquals(); + } + + @Test + public void basics() { + Device device = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1, CID); + validate(device); + } + + @Test + public void annotations() { + Device device = new DefaultDevice(PID, DID1, SWITCH, MFR, HW, SW, SN1, CID, + DefaultAnnotations.builder().set("foo", "bar").build()); + validate(device); + assertEquals("incorrect provider", "bar", device.annotations().value("foo")); + } + + private void validate(Device device) { + assertEquals("incorrect provider", PID, device.providerId()); + assertEquals("incorrect id", DID1, device.id()); + assertEquals("incorrect type", SWITCH, device.type()); + assertEquals("incorrect manufacturer", MFR, device.manufacturer()); + assertEquals("incorrect hw", HW, device.hwVersion()); + assertEquals("incorrect sw", SW, device.swVersion()); + assertEquals("incorrect serial", SN1, device.serialNumber()); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultEdgeLinkTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultEdgeLinkTest.java new file mode 100644 index 00000000..ee5b0e32 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultEdgeLinkTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 2014 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 com.google.common.testing.EqualsTester; +import org.junit.Test; +import org.onosproject.net.provider.ProviderId; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; +import static org.onosproject.net.DefaultLinkTest.cp; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.HostId.hostId; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Test of the default edge link model entity. + */ +public class DefaultEdgeLinkTest { + + private static final ProviderId PID = new ProviderId("of", "foo"); + private static final DeviceId DID1 = deviceId("of:foo"); + private static final HostId HID1 = hostId("00:00:00:00:00:01/-1"); + private static final HostId HID2 = hostId("00:00:00:00:00:01/-1"); + private static final PortNumber P0 = portNumber(0); + private static final PortNumber P1 = portNumber(1); + + @Test + public void testEquality() { + EdgeLink l1 = new DefaultEdgeLink(PID, cp(HID1, P0), + new HostLocation(DID1, P1, 123L), true); + EdgeLink l2 = new DefaultEdgeLink(PID, cp(HID1, P0), + new HostLocation(DID1, P1, 123L), true); + + EdgeLink l3 = new DefaultEdgeLink(PID, cp(HID2, P0), + new HostLocation(DID1, P1, 123L), false); + EdgeLink l4 = new DefaultEdgeLink(PID, cp(HID2, P0), + new HostLocation(DID1, P1, 123L), false); + + new EqualsTester().addEqualityGroup(l1, l2) + .addEqualityGroup(l3, l4) + .testEquals(); + } + + @Test + public void basics() { + HostLocation hostLocation = new HostLocation(DID1, P1, 123L); + EdgeLink link = new DefaultEdgeLink(PID, cp(HID1, P0), hostLocation, false); + assertEquals("incorrect src", cp(HID1, P0), link.dst()); + assertEquals("incorrect dst", hostLocation, link.src()); + assertEquals("incorrect type", Link.Type.EDGE, link.type()); + assertEquals("incorrect hostId", HID1, link.hostId()); + assertEquals("incorrect connect point", hostLocation, link.hostLocation()); + assertEquals("incorrect time", 123L, link.hostLocation().time()); + } + + @Test + public void phantomIngress() { + HostLocation hostLocation = new HostLocation(DID1, P1, 123L); + EdgeLink link = createEdgeLink(hostLocation, true); + assertEquals("incorrect dst", hostLocation, link.dst()); + assertEquals("incorrect type", Link.Type.EDGE, link.type()); + assertEquals("incorrect connect point", hostLocation, link.hostLocation()); + assertEquals("incorrect time", 123L, link.hostLocation().time()); + } + + @Test + public void phantomEgress() { + ConnectPoint hostLocation = new ConnectPoint(DID1, P1); + EdgeLink link = createEdgeLink(hostLocation, false); + assertEquals("incorrect src", hostLocation, link.src()); + assertEquals("incorrect type", Link.Type.EDGE, link.type()); + assertEquals("incorrect connect point", hostLocation, link.hostLocation()); + assertEquals("incorrect time", 0L, link.hostLocation().time()); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultHostTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultHostTest.java new file mode 100644 index 00000000..1fb6da5a --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultHostTest.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014 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 static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.google.common.testing.EqualsTester; + +public class DefaultHostTest extends TestDeviceParams { + + @Test + public void testEquality() { + Host h1 = new DefaultHost(PID, HID1, MAC1, VLAN1, LOC1, IPSET1); + Host h2 = new DefaultHost(PID, HID1, MAC1, VLAN1, LOC1, IPSET1); + Host h3 = new DefaultHost(PID, HID2, MAC2, VLAN2, LOC2, IPSET2); + Host h4 = new DefaultHost(PID, HID2, MAC2, VLAN2, LOC2, IPSET2); + Host h5 = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC2, IPSET1); + + new EqualsTester().addEqualityGroup(h1, h2) + .addEqualityGroup(h3, h4) + .addEqualityGroup(h5) + .testEquals(); + } + + @Test + public void basics() { + Host host = new DefaultHost(PID, HID1, MAC1, VLAN1, LOC1, IPSET1); + assertEquals("incorrect provider", PID, host.providerId()); + assertEquals("incorrect id", HID1, host.id()); + assertEquals("incorrect type", MAC1, host.mac()); + assertEquals("incorrect VLAN", VLAN1, host.vlan()); + assertEquals("incorrect location", LOC1, host.location()); + assertEquals("incorrect IP's", IPSET1, host.ipAddresses()); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultLinkTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultLinkTest.java new file mode 100644 index 00000000..bd5821bb --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultLinkTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2014 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 com.google.common.testing.EqualsTester; +import org.junit.Test; +import org.onosproject.net.provider.ProviderId; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.Link.Type.DIRECT; +import static org.onosproject.net.Link.Type.INDIRECT; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Test of the default link model entity. + */ +public class DefaultLinkTest { + + private static final ProviderId PID = new ProviderId("of", "foo"); + private static final DeviceId DID1 = deviceId("of:foo"); + private static final DeviceId DID2 = deviceId("of:bar"); + private static final PortNumber P1 = portNumber(1); + private static final PortNumber P2 = portNumber(2); + + public static ConnectPoint cp(ElementId id, PortNumber pn) { + return new ConnectPoint(id, pn); + } + + @Test + public void testEquality() { + Link l1 = new DefaultLink(PID, cp(DID1, P1), cp(DID2, P2), DIRECT); + Link l2 = new DefaultLink(PID, cp(DID1, P1), cp(DID2, P2), DIRECT); + Link l3 = new DefaultLink(PID, cp(DID1, P2), cp(DID2, P2), DIRECT); + Link l4 = new DefaultLink(PID, cp(DID1, P2), cp(DID2, P2), DIRECT); + Link l5 = new DefaultLink(PID, cp(DID1, P2), cp(DID2, P2), INDIRECT); + + new EqualsTester().addEqualityGroup(l1, l2) + .addEqualityGroup(l3, l4) + .addEqualityGroup(l5) + .testEquals(); + } + + @Test + public void basics() { + Link link = new DefaultLink(PID, cp(DID1, P1), cp(DID2, P2), DIRECT); + assertEquals("incorrect src", cp(DID1, P1), link.src()); + assertEquals("incorrect dst", cp(DID2, P2), link.dst()); + assertEquals("incorrect type", DIRECT, link.type()); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultPortTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultPortTest.java new file mode 100644 index 00000000..592115d7 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/DefaultPortTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2014 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 com.google.common.testing.EqualsTester; +import org.junit.Test; +import org.onosproject.net.provider.ProviderId; +import org.onlab.packet.ChassisId; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.net.Device.Type.SWITCH; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.Port.Type.COPPER; +import static org.onosproject.net.Port.Type.FIBER; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Test of the default port model entity. + */ +public class DefaultPortTest { + + private static final ProviderId PID = new ProviderId("of", "foo"); + private static final DeviceId DID1 = deviceId("of:foo"); + private static final DeviceId DID2 = deviceId("of:bar"); + private static final PortNumber P1 = portNumber(1); + private static final PortNumber P2 = portNumber(2); + private static final long SP1 = 1_000_000; + + @Test + public void testEquality() { + Device device = new DefaultDevice(PID, DID1, SWITCH, "m", "h", "s", "n", + new ChassisId()); + Port p1 = new DefaultPort(device, portNumber(1), true, COPPER, SP1); + Port p2 = new DefaultPort(device, portNumber(1), true, COPPER, SP1); + Port p3 = new DefaultPort(device, portNumber(2), true, FIBER, SP1); + Port p4 = new DefaultPort(device, portNumber(2), true, FIBER, SP1); + Port p5 = new DefaultPort(device, portNumber(1), false); + + new EqualsTester().addEqualityGroup(p1, p2) + .addEqualityGroup(p3, p4) + .addEqualityGroup(p5) + .testEquals(); + } + + @Test + public void basics() { + Device device = new DefaultDevice(PID, DID1, SWITCH, "m", "h", "s", "n", + new ChassisId()); + Port port = new DefaultPort(device, portNumber(1), true, FIBER, SP1); + assertEquals("incorrect element", device, port.element()); + assertEquals("incorrect number", portNumber(1), port.number()); + assertEquals("incorrect state", true, port.isEnabled()); + assertEquals("incorrect speed", SP1, port.portSpeed()); + assertEquals("incorrect type", FIBER, port.type()); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/DeviceIdTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/DeviceIdTest.java new file mode 100644 index 00000000..ab5373f8 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/DeviceIdTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 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 com.google.common.testing.EqualsTester; +import org.junit.Test; + +import static org.onosproject.net.DeviceId.deviceId; + +/** + * Test of the device identifier. + */ +public class DeviceIdTest { + + @Test + public void basics() { + new EqualsTester() + .addEqualityGroup(deviceId("of:foo"), + deviceId("of:foo")) + .addEqualityGroup(deviceId("of:bar")) + .testEquals(); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/HostIdTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/HostIdTest.java new file mode 100644 index 00000000..43425e21 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/HostIdTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014 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 com.google.common.testing.EqualsTester; + +import org.junit.Test; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; + +import static org.onosproject.net.HostId.hostId; + +/** + * Test for the host identifier. + */ +public class HostIdTest { + + private static final MacAddress MAC1 = MacAddress.valueOf("00:11:00:00:00:01"); + private static final MacAddress MAC2 = MacAddress.valueOf("00:22:00:00:00:02"); + private static final VlanId VLAN1 = VlanId.vlanId((short) 11); + private static final VlanId VLAN2 = VlanId.vlanId((short) 22); + + @Test + public void basics() { + new EqualsTester() + .addEqualityGroup(hostId(MAC1, VLAN1), hostId(MAC1, VLAN1)) + .addEqualityGroup(hostId(MAC2, VLAN2), hostId(MAC2, VLAN2)) + .testEquals(); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/IndexedLambdaTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/IndexedLambdaTest.java new file mode 100644 index 00000000..8cbe8232 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/IndexedLambdaTest.java @@ -0,0 +1,35 @@ +/* + * 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 com.google.common.testing.EqualsTester; +import org.junit.Test; + +/** + * Test for IndexedLambda. + */ +public class IndexedLambdaTest { + /** + * Tests equality of IndexedLambda instances. + */ + @Test + public void testEquality() { + new EqualsTester() + .addEqualityGroup(Lambda.indexedLambda(10), Lambda.indexedLambda(10)) + .addEqualityGroup(Lambda.indexedLambda(11), Lambda.indexedLambda(11), Lambda.indexedLambda(11)) + .testEquals(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/LinkKeyTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/LinkKeyTest.java new file mode 100644 index 00000000..4dfc1399 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/LinkKeyTest.java @@ -0,0 +1,129 @@ +/* + * Copyright 2014 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.junit.Test; + +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Unit tests for the LinkKey class. + */ +public class LinkKeyTest { + + static final DeviceId D1 = deviceId("1"); + static final DeviceId D2 = deviceId("2"); + static final PortNumber P1 = portNumber(1); + static final PortNumber P2 = portNumber(2); + + static final ConnectPoint SRC1 = new ConnectPoint(D1, P1); + static final ConnectPoint DST1 = new ConnectPoint(D2, P1); + static final ConnectPoint DST2 = new ConnectPoint(D2, P2); + + + /** + * Checks that the LinkKey class is immutable. + */ + @Test + public void testLinkKeyImmutability() { + assertThatClassIsImmutable(LinkKey.class); + } + + /** + * Check null source connection. + */ + @Test(expected = NullPointerException.class) + public void testNullSrc() { + LinkKey key = LinkKey.linkKey(null, DST1); + } + + /** + * Check null destination connection. + */ + @Test(expected = NullPointerException.class) + public void testNullDst() { + LinkKey key = LinkKey.linkKey(SRC1, null); + } + + /** + * Check that two LinkKeys based on the same source/destination pair compare + * equal. + */ + @Test + public void testCompareEquals() { + LinkKey k1 = LinkKey.linkKey(SRC1, DST2); + LinkKey k2 = LinkKey.linkKey(SRC1, DST2); + + assertThat(k1, is(equalTo(k2))); + } + + /** + * Check that two LinkKeys based on different source/destination pairs compare + * not equal. + */ + @Test + public void testCompareNotEquals() { + LinkKey k1 = LinkKey.linkKey(SRC1, DST1); + LinkKey k2 = LinkKey.linkKey(SRC1, DST2); + + assertThat(k1, is(not(equalTo(k2)))); + assertThat(k1, is(not(equalTo(new Object())))); + } + + /** + * Check that two LinkKeys based on the same source/destination pair compare + * equal. + */ + @Test + public void testHashCodeEquals() { + LinkKey k1 = LinkKey.linkKey(SRC1, DST2); + LinkKey k2 = LinkKey.linkKey(SRC1, DST2); + + assertThat(k1.hashCode(), is(equalTo(k2.hashCode()))); + } + + /** + * Check that two LinkKeys based on different source/destination pairs compare + * not equal. + */ + @Test + public void testHashCodeNotEquals() { + LinkKey k1 = LinkKey.linkKey(SRC1, DST1); + LinkKey k2 = LinkKey.linkKey(SRC1, DST2); + + assertThat(k1.hashCode(), is(not(equalTo(k2.hashCode())))); + } + + /** + * Check the toString() method of LinkKey. + */ + @Test + public void testToString() { + LinkKey k1 = LinkKey.linkKey(SRC1, DST1); + String k1String = k1.toString(); + assertThat(k1String, allOf(containsString("LinkKey{"), + containsString("src=ConnectPoint{elementId=1, portNumber=1}"), + containsString("dst=ConnectPoint{elementId=2, portNumber=1}"))); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/NetTestTools.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/NetTestTools.java new file mode 100644 index 00000000..176fe40c --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/NetTestTools.java @@ -0,0 +1,138 @@ +/* + * Copyright 2014-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.onlab.junit.TestUtils; +import org.onlab.packet.ChassisId; +import org.onosproject.TestApplicationId; +import org.onosproject.core.ApplicationId; +import org.onosproject.event.EventDeliveryService; +import org.onosproject.net.provider.ProviderId; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.onlab.packet.MacAddress.valueOf; +import static org.onlab.packet.VlanId.vlanId; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.HostId.hostId; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Miscellaneous tools for testing core related to the network model. + */ +public final class NetTestTools { + + private NetTestTools() { + } + + public static final ProviderId PID = new ProviderId("of", "foo"); + public static final ApplicationId APP_ID = new TestApplicationId("foo"); + + // Short-hand for producing a device id from a string + public static DeviceId did(String id) { + return deviceId("of:" + id); + } + + + // Short-hand for producing a host id from a string + public static HostId hid(String id) { + return hostId(id); + } + + // Crates a new device with the specified id + public static Device device(String id) { + return new DefaultDevice(PID, did(id), Device.Type.SWITCH, + "mfg", "1.0", "1.1", "1234", new ChassisId()); + } + + // Crates a new host with the specified id + public static Host host(String id, String did) { + return new DefaultHost(PID, hid(id), valueOf(1234), vlanId((short) 2), + new HostLocation(did(did), portNumber(1), 321), + new HashSet<>()); + } + + // Short-hand for creating a connection point. + public static ConnectPoint connectPoint(String id, int port) { + return new ConnectPoint(did(id), portNumber(port)); + } + + // Short-hand for creating a link. + public static Link link(String src, int sp, String dst, int dp) { + return new DefaultLink(PID, + connectPoint(src, sp), + connectPoint(dst, dp), + Link.Type.DIRECT); + } + + // Creates a path that leads through the given devices. + public static Path createPath(String... ids) { + List links = new ArrayList<>(); + for (int i = 0; i < ids.length - 1; i++) { + links.add(link(ids[i], i, ids[i + 1], i)); + } + return new DefaultPath(PID, links, ids.length); + } + + // Creates OCh signal + public static OchSignal createLambda() { + return new OchSignal(GridType.DWDM, ChannelSpacing.CHL_6P25GHZ, 8, 4); + } + + /** + * Verifies that Annotations created by merging {@code annotations} is + * equal to actual Annotations. + * + * @param actual annotations to check + * @param annotations expected annotations + */ + public static void assertAnnotationsEquals(Annotations actual, SparseAnnotations... annotations) { + DefaultAnnotations expected = DefaultAnnotations.builder().build(); + for (SparseAnnotations a : annotations) { + expected = DefaultAnnotations.merge(expected, a); + } + assertEquals(expected.keys(), actual.keys()); + for (String key : expected.keys()) { + assertEquals(expected.value(key), actual.value(key)); + } + } + + /** + * Injects the given event delivery service into the specified manager + * component. + * + * @param manager manager component + * @param svc service reference to be injected + */ + public static void injectEventDispatcher(Object manager, EventDeliveryService svc) { + Class mc = manager.getClass(); + for (Field f : mc.getSuperclass().getDeclaredFields()) { + if (f.getType().equals(EventDeliveryService.class)) { + try { + TestUtils.setField(manager, f.getName(), svc); + } catch (TestUtils.TestUtilsException e) { + throw new IllegalArgumentException("Unable to inject reference", e); + } + break; + } + } + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/OchSignalTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/OchSignalTest.java new file mode 100644 index 00000000..c171d523 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/OchSignalTest.java @@ -0,0 +1,40 @@ +/* + * 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 com.google.common.testing.EqualsTester; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Test for OchSignal. + */ +public class OchSignalTest { + + private final Lambda och1 = Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, 1, 1); + private final Lambda sameOch1 = Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, 1, 1); + private final Lambda och2 = Lambda.ochSignal(GridType.CWDM, ChannelSpacing.CHL_6P25GHZ, 4, 1); + private final Lambda sameOch2 = Lambda.ochSignal(GridType.CWDM, ChannelSpacing.CHL_6P25GHZ, 4, 1); + + @Test + public void testEquality() { + new EqualsTester() + .addEqualityGroup(och1, sameOch1) + .addEqualityGroup(och2, sameOch2) + .testEquals(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/PortNumberTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/PortNumberTest.java new file mode 100644 index 00000000..6f7b2c2d --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/PortNumberTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2014-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 com.google.common.testing.EqualsTester; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Test of the port number. + */ +public class PortNumberTest { + + @Test + public void basics() { + new EqualsTester() + .addEqualityGroup(portNumber(123), portNumber("123")) + .addEqualityGroup(portNumber(321), portNumber(321, "LIM-3-2-1")) + .testEquals(); + } + + @Test + public void number() { + assertEquals("incorrect long value", 12345, portNumber(12345).toLong()); + } + + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/TestDeviceParams.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/TestDeviceParams.java new file mode 100644 index 00000000..2d8aae3c --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/TestDeviceParams.java @@ -0,0 +1,55 @@ +/* + * Copyright 2014 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 static org.onosproject.net.DeviceId.deviceId; + +import java.util.Set; + +import org.onosproject.net.provider.ProviderId; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; + +import com.google.common.collect.Sets; + +/** + * Provides a set of test DefaultDevice parameters for use with Host- + * related tests. + */ +public abstract class TestDeviceParams { + + protected static final ProviderId PID = new ProviderId("of", "foo"); + protected static final DeviceId DID1 = deviceId("of:foo"); + protected static final DeviceId DID2 = deviceId("of:bar"); + protected static final MacAddress MAC1 = MacAddress.valueOf("00:11:00:00:00:01"); + protected static final MacAddress MAC2 = MacAddress.valueOf("00:22:00:00:00:02"); + protected static final VlanId VLAN1 = VlanId.vlanId((short) 11); + protected static final VlanId VLAN2 = VlanId.vlanId((short) 22); + protected static final IpAddress IP1 = IpAddress.valueOf("10.0.0.1"); + protected static final IpAddress IP2 = IpAddress.valueOf("10.0.0.2"); + protected static final IpAddress IP3 = IpAddress.valueOf("10.0.0.3"); + + protected static final PortNumber P1 = PortNumber.portNumber(100); + protected static final PortNumber P2 = PortNumber.portNumber(200); + protected static final HostId HID1 = HostId.hostId(MAC1, VLAN1); + protected static final HostId HID2 = HostId.hostId(MAC2, VLAN2); + protected static final HostLocation LOC1 = new HostLocation(DID1, P1, 123L); + protected static final HostLocation LOC2 = new HostLocation(DID2, P2, 123L); + protected static final Set IPSET1 = Sets.newHashSet(IP1, IP2); + protected static final Set IPSET2 = Sets.newHashSet(IP1, IP3); + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigRegistryAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigRegistryAdapter.java new file mode 100644 index 00000000..6201c0b6 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigRegistryAdapter.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014-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.config; + +import java.util.Set; + +/** + * Test adapter for network configuration service registry. + */ +public class NetworkConfigRegistryAdapter extends NetworkConfigServiceAdapter implements NetworkConfigRegistry { + + public void registerConfigFactory(ConfigFactory configFactory) { + } + + public void unregisterConfigFactory(ConfigFactory configFactory) { + } + + public Set getConfigFactories() { + return null; + } + + public > Set> getConfigFactories(Class subjectClass) { + return null; + } + + public > ConfigFactory getConfigFactory(Class configClass) { + return null; + } +} 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 new file mode 100644 index 00000000..b70d14e8 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/config/NetworkConfigServiceAdapter.java @@ -0,0 +1,90 @@ +/* + * 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.config; + +import com.fasterxml.jackson.databind.JsonNode; + +import java.util.Set; + +/** + * Test adapter for network configuration service. + */ +public class NetworkConfigServiceAdapter implements NetworkConfigService { + @Override + public Set getSubjectClasses() { + return null; + } + + @Override + public SubjectFactory getSubjectFactory(String subjectKey) { + return null; + } + + @Override + public SubjectFactory getSubjectFactory(Class subjectClass) { + return null; + } + + @Override + public Class getConfigClass(String subjectKey, String configKey) { + return null; + } + + @Override + public Set getSubjects(Class subjectClass) { + return null; + } + + @Override + public > Set getSubjects(Class subjectClass, Class configClass) { + return null; + } + + @Override + public Set> getConfigs(S subject) { + return null; + } + + @Override + public > C getConfig(S subject, Class configClass) { + return null; + } + + @Override + public > C addConfig(S subject, Class configClass) { + return null; + } + + @Override + public > C applyConfig(S subject, Class configClass, JsonNode json) { + return null; + } + + @Override + public > void removeConfig(S subject, Class configClass) { + + } + + @Override + public void addListener(NetworkConfigListener listener) { + + } + + @Override + public void removeListener(NetworkConfigListener listener) { + + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DefaultDeviceDescriptionTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DefaultDeviceDescriptionTest.java new file mode 100644 index 00000000..3dcdc22d --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DefaultDeviceDescriptionTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 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.device; + +import org.junit.Test; +import org.onlab.packet.ChassisId; + +import java.net.URI; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.onosproject.net.Device.Type.SWITCH; + +/** + * Test of the default device description. + */ +public class DefaultDeviceDescriptionTest { + + private static final URI DURI = URI.create("of:foo"); + private static final String MFR = "whitebox"; + private static final String HW = "1.1.x"; + private static final String SW = "3.9.1"; + private static final String SN = "43311-12345"; + private static final ChassisId CID = new ChassisId(); + + + @Test + public void basics() { + DeviceDescription device = + new DefaultDeviceDescription(DURI, SWITCH, MFR, HW, SW, SN, CID); + assertEquals("incorrect uri", DURI, device.deviceURI()); + assertEquals("incorrect type", SWITCH, device.type()); + assertEquals("incorrect manufacturer", MFR, device.manufacturer()); + assertEquals("incorrect hw", HW, device.hwVersion()); + assertEquals("incorrect sw", SW, device.swVersion()); + assertEquals("incorrect serial", SN, device.serialNumber()); + assertTrue("incorrect toString", device.toString().contains("uri=of:foo")); + assertTrue("Incorrect chassis", device.chassisId().value() == 0); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DefaultPortStatisticsTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DefaultPortStatisticsTest.java new file mode 100644 index 00000000..b691ebc3 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DefaultPortStatisticsTest.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.net.device; + +import java.lang.reflect.Constructor; +import java.util.Arrays; + +import org.junit.Assert; +import org.junit.Test; +import org.onosproject.net.NetTestTools; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +/** + * DefaultPortStatistics unit tests. + */ +public class DefaultPortStatisticsTest { + + private final PortStatistics stats1 = DefaultPortStatistics.builder() + .setBytesReceived(1) + .setBytesSent(2) + .setDurationNano(3) + .setDurationSec(4) + .setPacketsReceived(5) + .setPacketsSent(6) + .setPacketsRxDropped(7) + .setPacketsRxErrors(8) + .setPacketsTxDropped(9) + .setPacketsTxErrors(10) + .setPort(80) + .setDeviceId(NetTestTools.did("1")) + .build(); + + private final PortStatistics stats2 = DefaultPortStatistics.builder() + .setBytesReceived(1) + .setBytesSent(2) + .setDurationNano(3) + .setDurationSec(4) + .setPacketsReceived(5) + .setPacketsSent(6) + .setPacketsRxDropped(7) + .setPacketsRxErrors(8) + .setPacketsTxDropped(9) + .setPacketsTxErrors(11) + .setPort(80) + .setDeviceId(NetTestTools.did("1")) + .build(); + + /** + * Checks that the GroupOperation class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(DefaultPortStatistics.class); + } + + @Test + public void testConstruction() { + assertThat(stats1.bytesReceived(), is(1L)); + assertThat(stats1.bytesSent(), is(2L)); + assertThat(stats1.durationNano(), is(3L)); + assertThat(stats1.durationSec(), is(4L)); + assertThat(stats1.packetsReceived(), is(5L)); + assertThat(stats1.packetsSent(), is(6L)); + assertThat(stats1.packetsRxDropped(), is(7L)); + assertThat(stats1.packetsRxErrors(), is(8L)); + assertThat(stats1.packetsTxDropped(), is(9L)); + assertThat(stats1.packetsTxErrors(), is(10L)); + assertThat(stats1.port(), is(80)); + } + + /** + * Tests the equals, hashCode and toString methods using Guava EqualsTester. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(stats1, stats1) + .addEqualityGroup(stats2) + .testEquals(); + } + + /** + * Tests that the empty argument list constructor for serialization + * is present and creates a proper object. + */ + @Test + public void testSerializerConstructor() { + try { + Constructor[] constructors = DefaultPortStatistics.class.getDeclaredConstructors(); + assertThat(constructors, notNullValue()); + Arrays.stream(constructors).filter(ctor -> + ctor.getParameterTypes().length == 0) + .forEach(noParamsCtor -> { + try { + noParamsCtor.setAccessible(true); + DefaultPortStatistics stats = + (DefaultPortStatistics) noParamsCtor.newInstance(); + assertThat(stats, notNullValue()); + } catch (Exception e) { + Assert.fail("Exception instantiating no parameters constructor"); + } + }); + } catch (Exception e) { + Assert.fail("Exception looking up constructors"); + } + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DeviceClockServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DeviceClockServiceAdapter.java new file mode 100644 index 00000000..5bfdd76b --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DeviceClockServiceAdapter.java @@ -0,0 +1,21 @@ +package org.onosproject.net.device; + +import org.onosproject.net.DeviceId; +import org.onosproject.store.Timestamp; + +/** + * Test adapter for device clock service. + */ +public class DeviceClockServiceAdapter implements DeviceClockService { + + @Override + public boolean isTimestampAvailable(DeviceId deviceId) { + return false; + } + + @Override + public Timestamp getTimestamp(DeviceId deviceId) { + return null; + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DeviceEventTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DeviceEventTest.java new file mode 100644 index 00000000..a0fb9358 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DeviceEventTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014 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.device; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.net.DeviceId.deviceId; + +import org.junit.Test; +import org.onosproject.event.AbstractEventTest; +import org.onosproject.net.DefaultDevice; +import org.onosproject.net.DefaultPort; +import org.onosproject.net.Device; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.provider.ProviderId; +import org.onlab.packet.ChassisId; + +/** + * Tests of the device event. + */ +public class DeviceEventTest extends AbstractEventTest { + + private Device createDevice() { + return new DefaultDevice(new ProviderId("of", "foo"), deviceId("of:foo"), + Device.Type.SWITCH, "box", "hw", "sw", "sn", new ChassisId()); + } + + @Override + @Test + public void withTime() { + Device device = createDevice(); + Port port = new DefaultPort(device, PortNumber.portNumber(123), true); + DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, + device, port, 123L); + validateEvent(event, DeviceEvent.Type.DEVICE_ADDED, device, 123L); + assertEquals("incorrect port", port, event.port()); + } + + @Override + @Test + public void withoutTime() { + Device device = createDevice(); + Port port = new DefaultPort(device, PortNumber.portNumber(123), true); + long before = System.currentTimeMillis(); + DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device, port); + long after = System.currentTimeMillis(); + validateEvent(event, DeviceEvent.Type.DEVICE_ADDED, device, before, after); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DeviceServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DeviceServiceAdapter.java new file mode 100644 index 00000000..795e4c0a --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/device/DeviceServiceAdapter.java @@ -0,0 +1,110 @@ +/* + * Copyright 2014-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.device; + +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; + +import org.onosproject.net.Device; +import org.onosproject.net.Device.Type; +import org.onosproject.net.DeviceId; +import org.onosproject.net.MastershipRole; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; + +import java.util.Collections; +import java.util.List; + +/** + * Test adapter for device service. + */ +public class DeviceServiceAdapter implements DeviceService { + @Override + public int getDeviceCount() { + return 0; + } + + @Override + public Iterable getDevices() { + return Collections.emptyList(); + } + + @Override + public Iterable getAvailableDevices() { + return FluentIterable.from(getDevices()) + .filter(new Predicate() { + + @Override + public boolean apply(Device input) { + return isAvailable(input.id()); + } + }); + } + + @Override + public Device getDevice(DeviceId deviceId) { + return null; + } + + @Override + public MastershipRole getRole(DeviceId deviceId) { + return MastershipRole.NONE; + } + + @Override + public List getPorts(DeviceId deviceId) { + return Collections.emptyList(); + } + + @Override + public List getPortStatistics(DeviceId deviceId) { + return null; + } + + @Override + public List getPortDeltaStatistics(DeviceId deviceId) { + return null; + } + + @Override + public Port getPort(DeviceId deviceId, PortNumber portNumber) { + return null; + } + + @Override + public boolean isAvailable(DeviceId deviceId) { + return false; + } + + @Override + public void addListener(DeviceListener listener) { + } + + @Override + public void removeListener(DeviceListener listener) { + } + + @Override + public Iterable getDevices(Type type) { + return Collections.emptyList(); + } + + @Override + public Iterable getAvailableDevices(Type type) { + return Collections.emptyList(); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverDataTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverDataTest.java new file mode 100644 index 00000000..e3d69109 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverDataTest.java @@ -0,0 +1,78 @@ +/* + * 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.driver; + +import com.google.common.collect.ImmutableMap; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.net.DeviceId; + +import static org.junit.Assert.*; +import static org.onosproject.net.DeviceId.deviceId; + +public class DefaultDriverDataTest { + + public static final DeviceId DEVICE_ID = deviceId("of:0011223344556677"); + + DefaultDriver ddc; + DefaultDriverData data; + + @Before + public void setUp() { + ddc = new DefaultDriver("foo.bar", null, "Circus", "lux", "1.2a", + ImmutableMap.of(TestBehaviour.class, + TestBehaviourImpl.class), + ImmutableMap.of("foo", "bar")); + data = new DefaultDriverData(ddc, DEVICE_ID); + } + + @Test + public void basics() { + assertSame("incorrect driver", ddc, data.driver()); + assertEquals("incorrect device id", DEVICE_ID, data.deviceId()); + assertTrue("incorrect toString", data.toString().contains("foo.bar")); + } + + @Test + public void behaviour() { + TestBehaviour behaviour = data.behaviour(TestBehaviour.class); + assertTrue("incorrect behaviour", behaviour instanceof TestBehaviourImpl); + } + + @Test + public void setAndClearAnnotations() { + data.set("croc", "aqua"); + data.set("roo", "mars"); + data.set("dingo", "bat"); + assertEquals("incorrect property", "bat", data.value("dingo")); + data.clear("dingo", "roo"); + assertNull("incorrect property", data.value("dingo")); + assertNull("incorrect property", data.value("root")); + assertEquals("incorrect property", "aqua", data.value("croc")); + assertEquals("incorrect properties", 1, data.keys().size()); + } + + @Test + public void clearAllAnnotations() { + data.set("croc", "aqua"); + data.set("roo", "mars"); + data.set("dingo", "bat"); + assertEquals("incorrect property", "bat", data.value("dingo")); + data.clear(); + assertEquals("incorrect properties", 0, data.keys().size()); + } + +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverHandlerTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverHandlerTest.java new file mode 100644 index 00000000..717cda2e --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverHandlerTest.java @@ -0,0 +1,55 @@ +/* + * 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.driver; + +import com.google.common.collect.ImmutableMap; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +public class DefaultDriverHandlerTest { + + DefaultDriver ddc; + DefaultDriverData data; + DefaultDriverHandler handler; + + @Before + public void setUp() { + ddc = new DefaultDriver("foo.bar", null, "Circus", "lux", "1.2a", + ImmutableMap.of(TestBehaviour.class, + TestBehaviourImpl.class, + TestBehaviourTwo.class, + TestBehaviourTwoImpl.class), + ImmutableMap.of("foo", "bar")); + data = new DefaultDriverData(ddc, DefaultDriverDataTest.DEVICE_ID); + handler = new DefaultDriverHandler(data); + } + + @Test + public void basics() { + assertSame("incorrect data", data, handler.data()); + assertTrue("incorrect toString", handler.toString().contains("1.2a")); + } + + @Test + public void behaviour() { + TestBehaviourTwo behaviour = handler.behaviour(TestBehaviourTwo.class); + assertTrue("incorrect behaviour", behaviour instanceof TestBehaviourTwoImpl); + } + +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverProviderTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverProviderTest.java new file mode 100644 index 00000000..4568fd92 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverProviderTest.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.driver; + +import com.google.common.collect.ImmutableMap; +import org.junit.Test; + +import java.util.Set; + +import static com.google.common.collect.ImmutableSet.of; +import static org.junit.Assert.assertEquals; + +public class DefaultDriverProviderTest { + + @Test + public void basics() { + DefaultDriverProvider ddp = new DefaultDriverProvider(); + DefaultDriver one = new DefaultDriver("foo.bar", null, "Circus", "lux", "1.2a", + ImmutableMap.of(TestBehaviour.class, + TestBehaviourImpl.class), + ImmutableMap.of("foo", "bar")); + DefaultDriver two = new DefaultDriver("foo.bar", null, "", "", "", + ImmutableMap.of(TestBehaviourTwo.class, + TestBehaviourTwoImpl.class), + ImmutableMap.of("goo", "wee")); + DefaultDriver three = new DefaultDriver("goo.foo", null, "BigTop", "better", "2.2", + ImmutableMap.of(TestBehaviourTwo.class, + TestBehaviourTwoImpl.class), + ImmutableMap.of("goo", "gee")); + + ddp.addDrivers(of(one, two, three)); + + Set drivers = ddp.getDrivers(); + assertEquals("incorrect types", 2, drivers.size()); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverTest.java new file mode 100644 index 00000000..01cc7a16 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/DefaultDriverTest.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.driver; + +import com.google.common.collect.ImmutableMap; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.onosproject.net.driver.DefaultDriverDataTest.DEVICE_ID; + +public class DefaultDriverTest { + + @Test + public void basics() { + DefaultDriver ddp = new DefaultDriver("foo.base", null, "Circus", "lux", "1.2a", + ImmutableMap.of(TestBehaviour.class, + TestBehaviourImpl.class, + TestBehaviourTwo.class, + TestBehaviourTwoImpl.class), + ImmutableMap.of("foo", "bar")); + + DefaultDriver ddc = new DefaultDriver("foo.bar", ddp, "Circus", "lux", "1.2a", + ImmutableMap.of(), + ImmutableMap.of("foo", "bar")); + assertEquals("incorrect name", "foo.bar", ddc.name()); + assertEquals("incorrect parent", ddp, ddc.parent()); + assertEquals("incorrect mfr", "Circus", ddc.manufacturer()); + assertEquals("incorrect hw", "lux", ddc.hwVersion()); + assertEquals("incorrect sw", "1.2a", ddc.swVersion()); + + assertEquals("incorrect behaviour count", 2, ddp.behaviours().size()); + assertEquals("incorrect behaviour count", 0, ddc.behaviours().size()); + assertTrue("incorrect behaviour", ddc.hasBehaviour(TestBehaviour.class)); + + Behaviour b1 = ddc.createBehaviour(new DefaultDriverData(ddc, DEVICE_ID), TestBehaviour.class); + assertTrue("incorrect behaviour class", b1 instanceof TestBehaviourImpl); + + Behaviour b2 = ddc.createBehaviour(new DefaultDriverHandler(new DefaultDriverData(ddc, DEVICE_ID)), + TestBehaviourTwo.class); + assertTrue("incorrect behaviour class", b2 instanceof TestBehaviourTwoImpl); + + assertEquals("incorrect property count", 1, ddc.properties().size()); + assertEquals("incorrect key count", 1, ddc.keys().size()); + assertEquals("incorrect property", "bar", ddc.value("foo")); + + assertTrue("incorrect toString", ddc.toString().contains("lux")); + } + + @Test + public void merge() { + DefaultDriver one = new DefaultDriver("foo.bar", null, "Circus", "lux", "1.2a", + ImmutableMap.of(TestBehaviour.class, + TestBehaviourImpl.class), + ImmutableMap.of("foo", "bar")); + Driver ddc = + one.merge(new DefaultDriver("foo.bar", null, "", "", "", + ImmutableMap.of(TestBehaviourTwo.class, + TestBehaviourTwoImpl.class), + ImmutableMap.of("goo", "wee"))); + + assertEquals("incorrect name", "foo.bar", ddc.name()); + assertEquals("incorrect mfr", "Circus", ddc.manufacturer()); + assertEquals("incorrect hw", "lux", ddc.hwVersion()); + assertEquals("incorrect sw", "1.2a", ddc.swVersion()); + + assertEquals("incorrect behaviour count", 2, ddc.behaviours().size()); + assertTrue("incorrect behaviour", ddc.hasBehaviour(TestBehaviourTwo.class)); + + assertEquals("incorrect property count", 2, ddc.properties().size()); + assertEquals("incorrect key count", 2, ddc.keys().size()); + assertEquals("incorrect property", "wee", ddc.value("goo")); + + assertTrue("incorrect toString", ddc.toString().contains("Circus")); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviour.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviour.java new file mode 100644 index 00000000..632fae15 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviour.java @@ -0,0 +1,22 @@ +/* + * 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.driver; + +/** + * Test behaviour. + */ +public interface TestBehaviour extends Behaviour { +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourImpl.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourImpl.java new file mode 100644 index 00000000..ec5c66bc --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourImpl.java @@ -0,0 +1,22 @@ +/* + * 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.driver; + +/** + * Test behaviour. + */ +public class TestBehaviourImpl extends AbstractBehaviour implements TestBehaviour { +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourNoConstructorImpl.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourNoConstructorImpl.java new file mode 100644 index 00000000..20452368 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourNoConstructorImpl.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.driver; + +/** + * Bad test behaviour. + */ +public final class TestBehaviourNoConstructorImpl + extends AbstractBehaviour implements TestBehaviour { + private TestBehaviourNoConstructorImpl() { + + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourTwo.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourTwo.java new file mode 100644 index 00000000..3399f00c --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourTwo.java @@ -0,0 +1,22 @@ +/* + * 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.driver; + +/** + * Test behaviour. + */ +public interface TestBehaviourTwo extends HandlerBehaviour { +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourTwoImpl.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourTwoImpl.java new file mode 100644 index 00000000..746bcc87 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/TestBehaviourTwoImpl.java @@ -0,0 +1,22 @@ +/* + * 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.driver; + +/** + * Test behaviour. + */ +public class TestBehaviourTwoImpl extends AbstractHandlerBehaviour implements TestBehaviourTwo { +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/XmlDriverLoaderTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/XmlDriverLoaderTest.java new file mode 100644 index 00000000..f54e7411 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/driver/XmlDriverLoaderTest.java @@ -0,0 +1,80 @@ +/* + * 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.driver; + +import org.junit.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Iterator; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.onosproject.net.driver.DefaultDriverDataTest.DEVICE_ID; + +/** + * Tests of the XML driver loader implementation. + */ +public class XmlDriverLoaderTest { + + @Test + public void basics() throws IOException { + XmlDriverLoader loader = new XmlDriverLoader(getClass().getClassLoader()); + InputStream stream = getClass().getResourceAsStream("drivers.1.xml"); + DriverProvider provider = loader.loadDrivers(stream, null); + System.out.println(provider); + assertEquals("incorrect driver count", 2, provider.getDrivers().size()); + + Iterator iterator = provider.getDrivers().iterator(); + Driver driver = iterator.next(); + if (!driver.name().equals("foo.1")) { + driver = iterator.next(); + } + + assertEquals("incorrect driver name", "foo.1", driver.name()); + assertEquals("incorrect driver mfg", "Circus", driver.manufacturer()); + assertEquals("incorrect driver hw", "1.2a", driver.hwVersion()); + assertEquals("incorrect driver sw", "2.2", driver.swVersion()); + + assertEquals("incorrect driver behaviours", 1, driver.behaviours().size()); + assertTrue("incorrect driver behaviour", driver.hasBehaviour(TestBehaviour.class)); + + assertEquals("incorrect driver properties", 2, driver.properties().size()); + assertTrue("incorrect driver property", driver.properties().containsKey("p1")); + } + + @Test(expected = IOException.class) + public void badXML() throws IOException { + XmlDriverLoader loader = new XmlDriverLoader(getClass().getClassLoader()); + loader.loadDrivers(getClass().getResourceAsStream("drivers.bad.xml"), null); + } + + @Test(expected = IllegalArgumentException.class) + public void noClass() throws IOException { + XmlDriverLoader loader = new XmlDriverLoader(getClass().getClassLoader()); + loader.loadDrivers(getClass().getResourceAsStream("drivers.noclass.xml"), null); + } + + @Test(expected = IllegalArgumentException.class) + public void noConstructor() throws IOException { + XmlDriverLoader loader = new XmlDriverLoader(getClass().getClassLoader()); + InputStream stream = getClass().getResourceAsStream("drivers.noconstructor.xml"); + DriverProvider provider = loader.loadDrivers(stream, null); + Driver driver = provider.getDrivers().iterator().next(); + driver.createBehaviour(new DefaultDriverData(driver, DEVICE_ID), TestBehaviour.class); + } + +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/BatchOperationTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/BatchOperationTest.java new file mode 100644 index 00000000..9e142e59 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/BatchOperationTest.java @@ -0,0 +1,153 @@ +/* + * Copyright 2014-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 java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import org.junit.Test; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBaseClass; + +/** + * Unit tests for the BatchOperationTest object. + */ +public class BatchOperationTest { + + private enum TestType { + OP1, + OP2, + OP3 + } + + final TestEntry entry1 = new TestEntry(TestType.OP1, new TestTarget(1)); + final TestEntry entry2 = new TestEntry(TestType.OP2, new TestTarget(2)); + + + private static final class TestTarget { + private int id; + + private TestTarget(int id) { + this.id = id; + } + + @Override + public int hashCode() { + return id; + } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null) { + return false; + } + + if (getClass() != o.getClass()) { + return false; + } + TestTarget that = (TestTarget) o; + return this.id == that.id; + } + + } + + private static final class TestEntry extends BatchOperationEntry { + public TestEntry(TestType operator, TestTarget target) { + super(operator, target); + } + } + + private static final class TestOperation extends BatchOperation { + private TestOperation() { + super(); + } + + private TestOperation(Collection batchOperations) { + super(batchOperations); + } + } + + /** + * Checks that the DefaultFlowRule class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutableBaseClass(BatchOperation.class); + } + + /** + * Tests the equals(), hashCode() and toString() operations. + */ + @Test + public void testEquals() { + final List ops1 = new LinkedList<>(); + ops1.add(entry1); + final List ops2 = new LinkedList<>(); + ops2.add(entry2); + + final TestOperation op1 = new TestOperation(ops1); + final TestOperation sameAsOp1 = new TestOperation(ops1); + final TestOperation op2 = new TestOperation(ops2); + + new EqualsTester() + .addEqualityGroup(op1, sameAsOp1) + .addEqualityGroup(op2) + .testEquals(); + } + + /** + * Tests the constructors for a BatchOperation. + */ + @Test + public void testConstruction() { + final List ops = new LinkedList<>(); + ops.add(entry2); + + final TestOperation op1 = new TestOperation(); + assertThat(op1.size(), is(0)); + assertThat(op1.getOperations(), hasSize(0)); + + final TestOperation op2 = new TestOperation(ops); + op1.addOperation(entry1); + op1.addAll(op2); + assertThat(op1.size(), is(2)); + assertThat(op1.getOperations(), hasSize(2)); + + op2.clear(); + assertThat(op2.size(), is(0)); + assertThat(op2.getOperations(), hasSize(0)); + } + + /** + * Tests the constructor for BatchOperationEntries. + */ + @Test + public void testEntryConstruction() { + final TestEntry entry = new TestEntry(TestType.OP3, new TestTarget(3)); + + assertThat(entry.operator(), is(TestType.OP3)); + assertThat(entry.target().id, is(3)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultFlowEntryTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultFlowEntryTest.java new file mode 100644 index 00000000..412acb62 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultFlowEntryTest.java @@ -0,0 +1,161 @@ +/* + * Copyright 2014 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 java.util.concurrent.TimeUnit; + +import org.junit.Test; +import org.onosproject.net.intent.IntentTestsMocks; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.is; +import static org.onosproject.net.NetTestTools.did; + +/** + * Unit tests for the DefaultFlowEntry class. + */ +public class DefaultFlowEntryTest { + private static final IntentTestsMocks.MockSelector SELECTOR = + new IntentTestsMocks.MockSelector(); + private static final IntentTestsMocks.MockTreatment TREATMENT = + new IntentTestsMocks.MockTreatment(); + + private static DefaultFlowEntry makeFlowEntry(int uniqueValue) { + FlowRule rule = DefaultFlowRule.builder() + .forDevice(did("id" + Integer.toString(uniqueValue))) + .withSelector(SELECTOR) + .withTreatment(TREATMENT) + .withPriority(uniqueValue) + .withCookie(uniqueValue) + .makeTemporary(uniqueValue) + .build(); + + return new DefaultFlowEntry(rule, FlowEntry.FlowEntryState.ADDED, + uniqueValue, uniqueValue, uniqueValue); + } + + final DefaultFlowEntry defaultFlowEntry1 = makeFlowEntry(1); + final DefaultFlowEntry sameAsDefaultFlowEntry1 = makeFlowEntry(1); + final DefaultFlowEntry defaultFlowEntry2 = makeFlowEntry(2); + + /** + * Tests the equals, hashCode and toString methods using Guava EqualsTester. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(defaultFlowEntry1, sameAsDefaultFlowEntry1) + .addEqualityGroup(defaultFlowEntry2) + .testEquals(); + } + + /** + * Tests the construction of a default flow entry from a device id. + */ + @Test + public void testDeviceBasedObject() { + assertThat(defaultFlowEntry1.deviceId(), is(did("id1"))); + assertThat(defaultFlowEntry1.selector(), is(SELECTOR)); + assertThat(defaultFlowEntry1.treatment(), is(TREATMENT)); + assertThat(defaultFlowEntry1.timeout(), is(1)); + assertThat(defaultFlowEntry1.life(), is(1L)); + assertThat(defaultFlowEntry1.packets(), is(1L)); + assertThat(defaultFlowEntry1.bytes(), is(1L)); + assertThat(defaultFlowEntry1.state(), is(FlowEntry.FlowEntryState.ADDED)); + assertThat(defaultFlowEntry1.lastSeen(), + greaterThan(System.currentTimeMillis() - + TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS))); + } + + /** + * Tests the setters on a default flow entry object. + */ + @Test + public void testSetters() { + final DefaultFlowEntry entry = makeFlowEntry(1); + + entry.setLastSeen(); + entry.setState(FlowEntry.FlowEntryState.PENDING_REMOVE); + entry.setPackets(11); + entry.setBytes(22); + entry.setLife(33); + + assertThat(entry.deviceId(), is(did("id1"))); + assertThat(entry.selector(), is(SELECTOR)); + assertThat(entry.treatment(), is(TREATMENT)); + assertThat(entry.timeout(), is(1)); + assertThat(entry.life(), is(33L)); + assertThat(entry.packets(), is(11L)); + assertThat(entry.bytes(), is(22L)); + assertThat(entry.state(), is(FlowEntry.FlowEntryState.PENDING_REMOVE)); + assertThat(entry.lastSeen(), + greaterThan(System.currentTimeMillis() - + TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS))); + } + + /** + * Tests a default flow rule built for an error. + */ + @Test + public void testErrorObject() { + final DefaultFlowEntry errorEntry = + new DefaultFlowEntry(new IntentTestsMocks.MockFlowRule(1), + 111, + 222); + assertThat(errorEntry.errType(), is(111)); + assertThat(errorEntry.errCode(), is(222)); + assertThat(errorEntry.state(), is(FlowEntry.FlowEntryState.FAILED)); + assertThat(errorEntry.lastSeen(), + greaterThan(System.currentTimeMillis() - + TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS))); + } + + /** + * Tests a default flow entry constructed from a flow rule. + */ + @Test + public void testFlowBasedObject() { + final DefaultFlowEntry entry = + new DefaultFlowEntry(new IntentTestsMocks.MockFlowRule(1)); + assertThat(entry.priority(), is(1)); + assertThat(entry.appId(), is((short) 0)); + assertThat(entry.lastSeen(), + greaterThan(System.currentTimeMillis() - + TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS))); + } + + /** + * Tests a default flow entry constructed from a flow rule plus extra + * parameters. + */ + @Test + public void testFlowBasedObjectWithParameters() { + final DefaultFlowEntry entry = + new DefaultFlowEntry(new IntentTestsMocks.MockFlowRule(33), + FlowEntry.FlowEntryState.REMOVED, + 101, 102, 103); + assertThat(entry.state(), is(FlowEntry.FlowEntryState.REMOVED)); + assertThat(entry.life(), is(101L)); + assertThat(entry.packets(), is(102L)); + assertThat(entry.bytes(), is(103L)); + assertThat(entry.lastSeen(), + greaterThan(System.currentTimeMillis() - + TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS))); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultFlowRuleTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultFlowRuleTest.java new file mode 100644 index 00000000..62acd16a --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultFlowRuleTest.java @@ -0,0 +1,161 @@ +/* + * Copyright 2014 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.junit.Test; +import org.onosproject.core.DefaultGroupId; +import org.onosproject.net.intent.IntentTestsMocks; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBaseClass; +import static org.onosproject.net.NetTestTools.APP_ID; +import static org.onosproject.net.NetTestTools.did; + +/** + * Unit tests for the default flow rule class. + */ +public class DefaultFlowRuleTest { + private static final IntentTestsMocks.MockSelector SELECTOR = + new IntentTestsMocks.MockSelector(); + private static final IntentTestsMocks.MockTreatment TREATMENT = + new IntentTestsMocks.MockTreatment(); + + private static byte [] b = new byte[3]; + private static FlowRuleExtPayLoad payLoad = FlowRuleExtPayLoad.flowRuleExtPayLoad(b); + final FlowRule flowRule1 = new IntentTestsMocks.MockFlowRule(1, payLoad); + final FlowRule sameAsFlowRule1 = new IntentTestsMocks.MockFlowRule(1, payLoad); + final DefaultFlowRule defaultFlowRule1 = new DefaultFlowRule(flowRule1); + final DefaultFlowRule sameAsDefaultFlowRule1 = new DefaultFlowRule(sameAsFlowRule1); + + /** + * Checks that the DefaultFlowRule class is immutable but can be inherited + * from. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutableBaseClass(DefaultFlowRule.class); + } + + /** + * Tests the equals, hashCode and toString methods using Guava EqualsTester. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(defaultFlowRule1, sameAsDefaultFlowRule1) + .testEquals(); + } + + /** + * Tests creation of a DefaultFlowRule using a FlowRule constructor. + */ + @Test + public void testCreationFromFlowRule() { + assertThat(defaultFlowRule1.deviceId(), is(flowRule1.deviceId())); + assertThat(defaultFlowRule1.appId(), is(flowRule1.appId())); + assertThat(defaultFlowRule1.id(), is(flowRule1.id())); + assertThat(defaultFlowRule1.isPermanent(), is(flowRule1.isPermanent())); + assertThat(defaultFlowRule1.priority(), is(flowRule1.priority())); + assertThat(defaultFlowRule1.selector(), is(flowRule1.selector())); + assertThat(defaultFlowRule1.treatment(), is(flowRule1.treatment())); + assertThat(defaultFlowRule1.timeout(), is(flowRule1.timeout())); + assertThat(defaultFlowRule1.payLoad(), is(flowRule1.payLoad())); + } + + /** + * Tests creation of a DefaultFlowRule using a FlowId constructor. + */ + + @Test + public void testCreationWithFlowId() { + final FlowRule rule = + DefaultFlowRule.builder() + .forDevice(did("1")) + .withSelector(SELECTOR) + .withTreatment(TREATMENT) + .withPriority(22) + .makeTemporary(44) + .fromApp(APP_ID) + .build(); + + assertThat(rule.deviceId(), is(did("1"))); + assertThat(rule.isPermanent(), is(false)); + assertThat(rule.priority(), is(22)); + assertThat(rule.selector(), is(SELECTOR)); + assertThat(rule.treatment(), is(TREATMENT)); + assertThat(rule.timeout(), is(44)); + } + + + /** + * Tests creation of a DefaultFlowRule using a PayLoad constructor. + */ + @Test + public void testCreationWithPayLoadByFlowTable() { + final DefaultFlowRule rule = + new DefaultFlowRule(did("1"), null, + null, 22, APP_ID, + 44, false, payLoad); + assertThat(rule.deviceId(), is(did("1"))); + assertThat(rule.isPermanent(), is(false)); + assertThat(rule.priority(), is(22)); + assertThat(rule.timeout(), is(44)); + assertThat(defaultFlowRule1.payLoad(), is(payLoad)); + } + + /** + * Tests creation of a DefaultFlowRule using a PayLoad constructor. + */ + @Test + public void testCreationWithPayLoadByGroupTable() { + final DefaultFlowRule rule = + new DefaultFlowRule(did("1"), null, + null, 22, APP_ID, new DefaultGroupId(0), + 44, false, payLoad); + assertThat(rule.deviceId(), is(did("1"))); + assertThat(rule.isPermanent(), is(false)); + assertThat(rule.priority(), is(22)); + assertThat(rule.timeout(), is(44)); + assertThat(rule.groupId(), is(new DefaultGroupId(0))); + assertThat(defaultFlowRule1.payLoad(), is(payLoad)); + } + /** + * Tests the creation of a DefaultFlowRule using an AppId constructor. + */ + @Test + public void testCreationWithAppId() { + final FlowRule rule = + DefaultFlowRule.builder() + .forDevice(did("1")) + .withSelector(SELECTOR) + .withTreatment(TREATMENT) + .withPriority(22) + .fromApp(APP_ID) + .makeTemporary(44) + .build(); + + assertThat(rule.deviceId(), is(did("1"))); + assertThat(rule.isPermanent(), is(false)); + assertThat(rule.priority(), is(22)); + assertThat(rule.selector(), is(SELECTOR)); + assertThat(rule.treatment(), is(TREATMENT)); + assertThat(rule.timeout(), is(44)); + } +} 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 new file mode 100644 index 00000000..b871397b --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java @@ -0,0 +1,295 @@ +/* + * Copyright 2014-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 java.util.Set; + +import org.hamcrest.Description; +import org.hamcrest.Factory; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; +import org.junit.Test; +import org.onlab.packet.Ip6Address; +import org.onlab.packet.IpPrefix; +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 com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.net.flow.criteria.Criterion.Type; + +/** + * Unit tests for default traffic selector class. + */ +public class DefaultTrafficSelectorTest { + + /** + * Checks that the DefaultFlowRule class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(DefaultTrafficSelector.class); + } + + /** + * Tests equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + final short one = 1; + final short two = 2; + + final TrafficSelector selector1 = DefaultTrafficSelector.builder() + .add(Criteria.matchLambda(new IndexedLambda(one))) + .build(); + final TrafficSelector sameAsSelector1 = DefaultTrafficSelector.builder() + .add(Criteria.matchLambda(new IndexedLambda(one))) + .build(); + final TrafficSelector selector2 = DefaultTrafficSelector.builder() + .add(Criteria.matchLambda(new IndexedLambda(two))) + .build(); + + new EqualsTester() + .addEqualityGroup(selector1, sameAsSelector1) + .addEqualityGroup(selector2) + .testEquals(); + } + + /** + * Hamcrest matcher to check that a selector contains a + * Criterion with the specified type. + */ + public static final class CriterionExistsMatcher + extends TypeSafeMatcher { + private final Criterion.Type type; + + /** + * Constructs a matcher for the given criterion type. + * + * @param typeValue criterion type to match + */ + public CriterionExistsMatcher(Criterion.Type typeValue) { + type = typeValue; + } + + @Override + public boolean matchesSafely(TrafficSelector selector) { + final Set criteria = selector.criteria(); + + return notNullValue().matches(criteria) && + hasSize(1).matches(criteria) && + notNullValue().matches(selector.getCriterion(type)); + } + + @Override + public void describeTo(Description description) { + description.appendText("a criterion with type \" "). + appendText(type.toString()). + appendText("\""); + } + } + + + /** + * Creates a criterion type matcher. Returns a matcher + * for a criterion with the given type. + * + * @param type type of Criterion to match + * @return Matcher object + */ + @Factory + public static Matcher hasCriterionWithType(Criterion.Type type) { + return new CriterionExistsMatcher(type); + } + + + /** + * Tests the builder functions that add specific criteria. + */ + @Test + public void testCriteriaCreation() { + TrafficSelector selector; + + final long longValue = 0x12345678; + final int intValue = 22; + final short shortValue = 33; + final byte byteValue = 44; + final byte dscpValue = 0xf; + final byte ecnValue = 3; + final MacAddress macValue = MacAddress.valueOf("11:22:33:44:55:66"); + final IpPrefix ipPrefixValue = IpPrefix.valueOf("192.168.1.0/24"); + final IpPrefix ipv6PrefixValue = IpPrefix.valueOf("fe80::1/64"); + final Ip6Address ipv6AddressValue = Ip6Address.valueOf("fe80::1"); + + selector = DefaultTrafficSelector.builder() + .matchInPort(PortNumber.portNumber(11)).build(); + assertThat(selector, hasCriterionWithType(Type.IN_PORT)); + + selector = DefaultTrafficSelector.builder() + .matchInPhyPort(PortNumber.portNumber(11)).build(); + assertThat(selector, hasCriterionWithType(Type.IN_PHY_PORT)); + + selector = DefaultTrafficSelector.builder() + .matchMetadata(longValue).build(); + assertThat(selector, hasCriterionWithType(Type.METADATA)); + + selector = DefaultTrafficSelector.builder() + .matchEthDst(macValue).build(); + assertThat(selector, hasCriterionWithType(Type.ETH_DST)); + + selector = DefaultTrafficSelector.builder() + .matchEthSrc(macValue).build(); + assertThat(selector, hasCriterionWithType(Type.ETH_SRC)); + + selector = DefaultTrafficSelector.builder() + .matchEthType(shortValue).build(); + assertThat(selector, hasCriterionWithType(Type.ETH_TYPE)); + + selector = DefaultTrafficSelector.builder() + .matchVlanId(VlanId.vlanId(shortValue)).build(); + assertThat(selector, hasCriterionWithType(Type.VLAN_VID)); + + selector = DefaultTrafficSelector.builder() + .matchVlanPcp(byteValue).build(); + assertThat(selector, hasCriterionWithType(Type.VLAN_PCP)); + + selector = DefaultTrafficSelector.builder() + .matchIPDscp(dscpValue).build(); + assertThat(selector, hasCriterionWithType(Type.IP_DSCP)); + + selector = DefaultTrafficSelector.builder() + .matchIPEcn(ecnValue).build(); + assertThat(selector, hasCriterionWithType(Type.IP_ECN)); + + selector = DefaultTrafficSelector.builder() + .matchIPProtocol(byteValue).build(); + assertThat(selector, hasCriterionWithType(Type.IP_PROTO)); + + selector = DefaultTrafficSelector.builder() + .matchIPSrc(ipPrefixValue).build(); + assertThat(selector, hasCriterionWithType(Type.IPV4_SRC)); + + selector = DefaultTrafficSelector.builder() + .matchIPDst(ipPrefixValue).build(); + assertThat(selector, hasCriterionWithType(Type.IPV4_DST)); + + selector = DefaultTrafficSelector.builder() + .matchTcpSrc(TpPort.tpPort(intValue)).build(); + assertThat(selector, hasCriterionWithType(Type.TCP_SRC)); + + selector = DefaultTrafficSelector.builder() + .matchTcpDst(TpPort.tpPort(intValue)).build(); + assertThat(selector, hasCriterionWithType(Type.TCP_DST)); + + selector = DefaultTrafficSelector.builder() + .matchUdpSrc(TpPort.tpPort(intValue)).build(); + assertThat(selector, hasCriterionWithType(Type.UDP_SRC)); + + selector = DefaultTrafficSelector.builder() + .matchUdpDst(TpPort.tpPort(intValue)).build(); + assertThat(selector, hasCriterionWithType(Type.UDP_DST)); + + selector = DefaultTrafficSelector.builder() + .matchSctpSrc(TpPort.tpPort(intValue)).build(); + assertThat(selector, hasCriterionWithType(Type.SCTP_SRC)); + + selector = DefaultTrafficSelector.builder() + .matchSctpDst(TpPort.tpPort(intValue)).build(); + assertThat(selector, hasCriterionWithType(Type.SCTP_DST)); + + selector = DefaultTrafficSelector.builder() + .matchIcmpType(byteValue).build(); + assertThat(selector, hasCriterionWithType(Type.ICMPV4_TYPE)); + + selector = DefaultTrafficSelector.builder() + .matchIcmpCode(byteValue).build(); + assertThat(selector, hasCriterionWithType(Type.ICMPV4_CODE)); + + selector = DefaultTrafficSelector.builder() + .matchIPv6Src(ipv6PrefixValue).build(); + assertThat(selector, hasCriterionWithType(Type.IPV6_SRC)); + + selector = DefaultTrafficSelector.builder() + .matchIPv6Dst(ipv6PrefixValue).build(); + assertThat(selector, hasCriterionWithType(Type.IPV6_DST)); + + selector = DefaultTrafficSelector.builder() + .matchIPv6FlowLabel(intValue).build(); + assertThat(selector, hasCriterionWithType(Type.IPV6_FLABEL)); + + selector = DefaultTrafficSelector.builder() + .matchIcmpv6Type(byteValue).build(); + assertThat(selector, hasCriterionWithType(Type.ICMPV6_TYPE)); + + selector = DefaultTrafficSelector.builder() + .matchIPv6NDTargetAddress(ipv6AddressValue).build(); + assertThat(selector, hasCriterionWithType(Type.IPV6_ND_TARGET)); + + selector = DefaultTrafficSelector.builder() + .matchIPv6NDSourceLinkLayerAddress(macValue).build(); + assertThat(selector, hasCriterionWithType(Type.IPV6_ND_SLL)); + + selector = DefaultTrafficSelector.builder() + .matchIPv6NDTargetLinkLayerAddress(macValue).build(); + assertThat(selector, hasCriterionWithType(Type.IPV6_ND_TLL)); + + selector = DefaultTrafficSelector.builder() + .matchMplsLabel(MplsLabel.mplsLabel(3)).build(); + assertThat(selector, hasCriterionWithType(Type.MPLS_LABEL)); + + selector = DefaultTrafficSelector.builder() + .matchIPv6ExthdrFlags(Criterion.IPv6ExthdrFlags.NONEXT.getValue()).build(); + assertThat(selector, hasCriterionWithType(Type.IPV6_EXTHDR)); + + 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/DefaultTrafficTreatmentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficTreatmentTest.java new file mode 100644 index 00000000..288f5f2f --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficTreatmentTest.java @@ -0,0 +1,124 @@ +/* + * Copyright 2014-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 com.google.common.testing.EqualsTester; +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; +import org.onosproject.net.IndexedLambda; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.Instructions; + +import java.util.List; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; + +/** + * Unit tests for the DefaultTrafficTreatment class. + */ +public class DefaultTrafficTreatmentTest { + + // Tests for the nested Builder class + + /** + * Tests that the Builder constructors return equivalent objects + * when given the same data. + */ + @Test + public void testTreatmentBuilderConstructors() { + final TrafficTreatment treatment1 = + DefaultTrafficTreatment.builder() + .add(Instructions.modL0Lambda(new IndexedLambda(4))) + .build(); + final TrafficTreatment treatment2 = + DefaultTrafficTreatment.builder(treatment1).build(); + assertThat(treatment1, is(equalTo(treatment2))); + } + + /** + * Tests methods defined on the Builder. + */ + @Test + public void testBuilderMethods() { + final Instruction instruction1 = + Instructions.modL0Lambda(new IndexedLambda(4)); + + final TrafficTreatment.Builder builder1 = + DefaultTrafficTreatment.builder() + .add(instruction1) + .setEthDst(MacAddress.BROADCAST) + .setEthSrc(MacAddress.BROADCAST) + .setIpDst(IpAddress.valueOf("1.1.1.1")) + .setIpSrc(IpAddress.valueOf("2.2.2.2")) + .add(Instructions.modL0Lambda(new IndexedLambda(4))) + .setOutput(PortNumber.portNumber(2)) + .setVlanId(VlanId.vlanId((short) 4)) + .setVlanPcp((byte) 3); + + final TrafficTreatment treatment1 = builder1.build(); + + final List instructions1 = treatment1.immediate(); + assertThat(instructions1, hasSize(9)); + + builder1.drop(); + builder1.add(instruction1); + + final List instructions2 = builder1.build().immediate(); + assertThat(instructions2, hasSize(11)); + + builder1.deferred() + .popVlan() + .pushVlan() + .setVlanId(VlanId.vlanId((short) 5)); + + final List instructions3 = builder1.build().immediate(); + assertThat(instructions3, hasSize(11)); + final List instructions4 = builder1.build().deferred(); + assertThat(instructions4, hasSize(3)); + } + + /** + * Tests equals(), hashCode() and toString() methods of + * DefaultTrafficTreatment. + */ + @Test + public void testEquals() { + final IndexedLambda lambda1 = new IndexedLambda(4); + final IndexedLambda lambda2 = new IndexedLambda(5); + final TrafficTreatment treatment1 = + DefaultTrafficTreatment.builder() + .add(Instructions.modL0Lambda(lambda1)) + .build(); + final TrafficTreatment sameAsTreatment1 = + DefaultTrafficTreatment.builder() + .add(Instructions.modL0Lambda(lambda1)) + .build(); + final TrafficTreatment treatment2 = + DefaultTrafficTreatment.builder() + .add(Instructions.modL0Lambda(lambda2)) + .build(); + new EqualsTester() + .addEqualityGroup(treatment1, sameAsTreatment1) + .addEqualityGroup(treatment2) + .testEquals(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowIdTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowIdTest.java new file mode 100644 index 00000000..263d4031 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowIdTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2014 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.junit.Test; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +/** + * Unit tests for flow id class. + */ +public class FlowIdTest { + + final FlowId flowId1 = FlowId.valueOf(1); + final FlowId sameAsFlowId1 = FlowId.valueOf(1); + final FlowId flowId2 = FlowId.valueOf(2); + + /** + * Checks that the FlowId class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(FlowId.class); + } + + /** + * Checks the operation of equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(flowId1, sameAsFlowId1) + .addEqualityGroup(flowId2) + .testEquals(); + } + + /** + * Checks the construction of a FlowId object. + */ + @Test + public void testConstruction() { + final long flowIdValue = 7777L; + final FlowId flowId = FlowId.valueOf(flowIdValue); + assertThat(flowId, is(notNullValue())); + assertThat(flowId.value(), is(flowIdValue)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleBatchOperationTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleBatchOperationTest.java new file mode 100644 index 00000000..4fa3492a --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleBatchOperationTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 2014-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 java.util.LinkedList; + +import org.junit.Test; +import org.onosproject.net.intent.IntentTestsMocks; + +import com.google.common.testing.EqualsTester; + +/** + * Unit tests for flow rule batch classes. + */ +public class FlowRuleBatchOperationTest { + + /** + * Tests the equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + final FlowRule rule = new IntentTestsMocks.MockFlowRule(1); + final FlowRuleBatchEntry entry1 = new FlowRuleBatchEntry( + FlowRuleBatchEntry.FlowRuleOperation.ADD, rule); + final FlowRuleBatchEntry entry2 = new FlowRuleBatchEntry( + FlowRuleBatchEntry.FlowRuleOperation.MODIFY, rule); + final FlowRuleBatchEntry entry3 = new FlowRuleBatchEntry( + FlowRuleBatchEntry.FlowRuleOperation.REMOVE, rule); + final LinkedList ops1 = new LinkedList<>(); + ops1.add(entry1); + final LinkedList ops2 = new LinkedList<>(); + ops1.add(entry2); + final LinkedList ops3 = new LinkedList<>(); + ops3.add(entry3); + + final FlowRuleBatchOperation operation1 = new FlowRuleBatchOperation(ops1, null, 0); + final FlowRuleBatchOperation sameAsOperation1 = new FlowRuleBatchOperation(ops1, null, 0); + final FlowRuleBatchOperation operation2 = new FlowRuleBatchOperation(ops2, null, 0); + final FlowRuleBatchOperation operation3 = new FlowRuleBatchOperation(ops3, null, 0); + + new EqualsTester() + .addEqualityGroup(operation1, sameAsOperation1) + .addEqualityGroup(operation2) + .addEqualityGroup(operation3) + .testEquals(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleBatchRequestTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleBatchRequestTest.java new file mode 100644 index 00000000..b379a6ec --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleBatchRequestTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014-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.junit.Test; +import org.onosproject.net.intent.IntentTestsMocks; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.ADD; +import static org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation.REMOVE; + +/** + * Unit tests for the FlowRuleBatchRequest class. + */ +public class FlowRuleBatchRequestTest { + + /** + * Tests that construction of FlowRuleBatchRequest objects returns the + * correct objects. + */ + @Test + public void testConstruction() { + final FlowRule rule1 = new IntentTestsMocks.MockFlowRule(1); + final FlowRule rule2 = new IntentTestsMocks.MockFlowRule(2); + final Set batch = new HashSet<>(); + batch.add(new FlowRuleBatchEntry(ADD, rule1)); + + batch.add(new FlowRuleBatchEntry(REMOVE, rule2)); + + + final FlowRuleBatchRequest request = + new FlowRuleBatchRequest(1, batch); + + assertThat(request.ops(), hasSize(2)); + assertThat(request.batchId(), is(1L)); + + final FlowRuleBatchOperation op = request.asBatchOperation(rule1.deviceId()); + assertThat(op.size(), is(2)); + + final List ops = op.getOperations(); + assertThat(ops, hasSize(2)); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleEventTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleEventTest.java new file mode 100644 index 00000000..2d79c893 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleEventTest.java @@ -0,0 +1,77 @@ +/* + * Copyright 2014 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 java.util.concurrent.TimeUnit; + +import org.junit.Test; +import org.onosproject.event.AbstractEventTest; +import org.onosproject.net.intent.IntentTestsMocks; + +import com.google.common.testing.EqualsTester; + +/** + * Unit Tests for the FlowRuleEvent class. + */ +public class FlowRuleEventTest extends AbstractEventTest { + + @Test + public void testEquals() { + final FlowRule flowRule1 = new IntentTestsMocks.MockFlowRule(1); + final FlowRule flowRule2 = new IntentTestsMocks.MockFlowRule(2); + final long time = 123L; + final FlowRuleEvent event1 = + new FlowRuleEvent(FlowRuleEvent.Type.RULE_ADDED, flowRule1, time); + final FlowRuleEvent sameAsEvent1 = + new FlowRuleEvent(FlowRuleEvent.Type.RULE_ADDED, flowRule1, time); + final FlowRuleEvent event2 = + new FlowRuleEvent(FlowRuleEvent.Type.RULE_ADD_REQUESTED, + flowRule2, time); + + // Equality for events is based on Object, these should all compare + // as different. + new EqualsTester() + .addEqualityGroup(event1) + .addEqualityGroup(sameAsEvent1) + .addEqualityGroup(event2) + .testEquals(); + } + + /** + * Tests the constructor where a time is passed in. + */ + @Test + public void testTimeConstructor() { + final long time = 123L; + final FlowRule flowRule = new IntentTestsMocks.MockFlowRule(1); + final FlowRuleEvent event = + new FlowRuleEvent(FlowRuleEvent.Type.RULE_REMOVE_REQUESTED, flowRule, time); + validateEvent(event, FlowRuleEvent.Type.RULE_REMOVE_REQUESTED, flowRule, time); + } + + /** + * Tests the constructor with the default time value. + */ + @Test + public void testConstructor() { + final long time = System.currentTimeMillis(); + final FlowRule flowRule = new IntentTestsMocks.MockFlowRule(1); + final FlowRuleEvent event = + new FlowRuleEvent(FlowRuleEvent.Type.RULE_UPDATED, flowRule); + validateEvent(event, FlowRuleEvent.Type.RULE_UPDATED, flowRule, time, + time + TimeUnit.SECONDS.toMillis(30)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleExtPayLoadTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleExtPayLoadTest.java new file mode 100644 index 00000000..30326a2e --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleExtPayLoadTest.java @@ -0,0 +1,36 @@ +package org.onosproject.net.flow; + +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import org.junit.Test; + +import com.google.common.testing.EqualsTester; +/** + * Test for FlowRuleExtPayLoad. + */ +public class FlowRuleExtPayLoadTest { + final byte[] b = new byte[3]; + final byte[] b1 = new byte[5]; + final FlowRuleExtPayLoad payLoad1 = FlowRuleExtPayLoad.flowRuleExtPayLoad(b); + final FlowRuleExtPayLoad sameAsPayLoad1 = FlowRuleExtPayLoad.flowRuleExtPayLoad(b); + final FlowRuleExtPayLoad payLoad2 = FlowRuleExtPayLoad.flowRuleExtPayLoad(b1); + + /** + * Checks that the FlowRuleExtPayLoad class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(FlowRuleExtPayLoad.class); + } + + /** + * Checks the operation of equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(payLoad1, sameAsPayLoad1) + .addEqualityGroup(payLoad2) + .testEquals(); + } +} 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 new file mode 100644 index 00000000..c7b78791 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/FlowRuleServiceAdapter.java @@ -0,0 +1,75 @@ +/* + * 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.core.ApplicationId; +import org.onosproject.net.DeviceId; + +/** + * Test adapter for flow rule service. + */ +public class FlowRuleServiceAdapter implements FlowRuleService { + @Override + public int getFlowRuleCount() { + return 0; + } + + @Override + public Iterable getFlowEntries(DeviceId deviceId) { + return null; + } + + @Override + public void applyFlowRules(FlowRule... flowRules) { + + } + + @Override + public void removeFlowRules(FlowRule... flowRules) { + + } + + @Override + public void removeFlowRulesById(ApplicationId appId) { + + } + + @Override + public Iterable getFlowRulesById(ApplicationId id) { + return null; + } + + @Override + public Iterable getFlowRulesByGroupId(ApplicationId appId, short groupId) { + return null; + } + + @Override + public void apply(FlowRuleOperations ops) { + + } + + @Override + public void addListener(FlowRuleListener listener) { + + } + + @Override + public void removeListener(FlowRuleListener listener) { + + } +} 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 new file mode 100644 index 00000000..ee294f6f --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java @@ -0,0 +1,1138 @@ +/* + * Copyright 2014-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.criteria; + +import org.junit.Test; +import org.onlab.packet.EthType; +import org.onlab.packet.Ip6Address; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.TpPort; +import org.onlab.packet.VlanId; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.GridType; +import org.onosproject.net.Lambda; +import org.onosproject.net.PortNumber; + +import com.google.common.testing.EqualsTester; +import org.onosproject.net.OchSignalType; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onlab.junit.UtilityClassChecker.assertThatClassIsUtility; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Unit tests for the Criteria class and its subclasses. + */ +public class CriteriaTest { + + final PortNumber port1 = portNumber(1); + final PortNumber port2 = portNumber(2); + + Criterion matchInPort1 = Criteria.matchInPort(port1); + Criterion sameAsMatchInPort1 = Criteria.matchInPort(port1); + Criterion matchInPort2 = Criteria.matchInPort(port2); + + Criterion matchInPhyPort1 = Criteria.matchInPhyPort(port1); + Criterion sameAsMatchInPhyPort1 = Criteria.matchInPhyPort(port1); + Criterion matchInPhyPort2 = Criteria.matchInPhyPort(port2); + + long metadata1 = 1; + long metadata2 = 2; + Criterion matchMetadata1 = Criteria.matchMetadata(metadata1); + Criterion sameAsMatchMetadata1 = Criteria.matchMetadata(metadata1); + Criterion matchMetadata2 = Criteria.matchMetadata(metadata2); + + private static final String MAC1 = "00:00:00:00:00:01"; + private static final String MAC2 = "00:00:00:00:00:02"; + private MacAddress mac1 = MacAddress.valueOf(MAC1); + private MacAddress mac2 = MacAddress.valueOf(MAC2); + Criterion matchEth1 = Criteria.matchEthSrc(mac1); + Criterion sameAsMatchEth1 = Criteria.matchEthSrc(mac1); + Criterion matchEth2 = Criteria.matchEthDst(mac2); + + int ethType1 = 1; + int ethType2 = 2; + Criterion matchEthType1 = Criteria.matchEthType(ethType1); + Criterion sameAsMatchEthType1 = Criteria.matchEthType(ethType1); + Criterion matchEthType2 = Criteria.matchEthType(ethType2); + + short vlan1 = 1; + short vlan2 = 2; + VlanId vlanId1 = VlanId.vlanId(vlan1); + VlanId vlanId2 = VlanId.vlanId(vlan2); + Criterion matchVlanId1 = Criteria.matchVlanId(vlanId1); + Criterion sameAsMatchVlanId1 = Criteria.matchVlanId(vlanId1); + Criterion matchVlanId2 = Criteria.matchVlanId(vlanId2); + + byte vlanPcp1 = 1; + byte vlanPcp2 = 2; + Criterion matchVlanPcp1 = Criteria.matchVlanPcp(vlanPcp1); + Criterion sameAsMatchVlanPcp1 = Criteria.matchVlanPcp(vlanPcp1); + Criterion matchVlanPcp2 = Criteria.matchVlanPcp(vlanPcp2); + + byte ipDscp1 = 1; + byte ipDscp2 = 2; + Criterion matchIpDscp1 = Criteria.matchIPDscp(ipDscp1); + Criterion sameAsMatchIpDscp1 = Criteria.matchIPDscp(ipDscp1); + Criterion matchIpDscp2 = Criteria.matchIPDscp(ipDscp2); + + byte ipEcn1 = 1; + byte ipEcn2 = 2; + Criterion matchIpEcn1 = Criteria.matchIPEcn(ipEcn1); + Criterion sameAsMatchIpEcn1 = Criteria.matchIPEcn(ipEcn1); + Criterion matchIpEcn2 = Criteria.matchIPEcn(ipEcn2); + + short protocol1 = 1; + short protocol2 = 2; + Criterion matchIpProtocol1 = Criteria.matchIPProtocol(protocol1); + Criterion sameAsMatchIpProtocol1 = Criteria.matchIPProtocol(protocol1); + Criterion matchIpProtocol2 = Criteria.matchIPProtocol(protocol2); + + private static final String IP1 = "1.2.3.4/24"; + private static final String IP2 = "5.6.7.8/24"; + private static final String IPV61 = "fe80::1/64"; + private static final String IPV62 = "fc80::2/64"; + private IpPrefix ip1 = IpPrefix.valueOf(IP1); + private IpPrefix ip2 = IpPrefix.valueOf(IP2); + private IpPrefix ipv61 = IpPrefix.valueOf(IPV61); + private IpPrefix ipv62 = IpPrefix.valueOf(IPV62); + Criterion matchIp1 = Criteria.matchIPSrc(ip1); + Criterion sameAsMatchIp1 = Criteria.matchIPSrc(ip1); + Criterion matchIp2 = Criteria.matchIPSrc(ip2); + Criterion matchIpv61 = Criteria.matchIPSrc(ipv61); + Criterion sameAsMatchIpv61 = Criteria.matchIPSrc(ipv61); + Criterion matchIpv62 = Criteria.matchIPSrc(ipv62); + + private TpPort tpPort1 = TpPort.tpPort(1); + private TpPort tpPort2 = TpPort.tpPort(2); + Criterion matchTcpPort1 = Criteria.matchTcpSrc(tpPort1); + Criterion sameAsMatchTcpPort1 = Criteria.matchTcpSrc(tpPort1); + Criterion matchTcpPort2 = Criteria.matchTcpDst(tpPort2); + + Criterion matchUdpPort1 = Criteria.matchUdpSrc(tpPort1); + Criterion sameAsMatchUdpPort1 = Criteria.matchUdpSrc(tpPort1); + Criterion matchUdpPort2 = Criteria.matchUdpDst(tpPort2); + + Criterion matchSctpPort1 = Criteria.matchSctpSrc(tpPort1); + Criterion sameAsMatchSctpPort1 = Criteria.matchSctpSrc(tpPort1); + Criterion matchSctpPort2 = Criteria.matchSctpDst(tpPort2); + + short icmpType1 = 1; + short icmpType2 = 2; + Criterion matchIcmpType1 = Criteria.matchIcmpType(icmpType1); + Criterion sameAsMatchIcmpType1 = Criteria.matchIcmpType(icmpType1); + Criterion matchIcmpType2 = Criteria.matchIcmpType(icmpType2); + + short icmpCode1 = 1; + short icmpCode2 = 2; + Criterion matchIcmpCode1 = Criteria.matchIcmpCode(icmpCode1); + Criterion sameAsMatchIcmpCode1 = Criteria.matchIcmpCode(icmpCode1); + Criterion matchIcmpCode2 = Criteria.matchIcmpCode(icmpCode2); + + int flowLabel1 = 1; + int flowLabel2 = 2; + Criterion matchFlowLabel1 = Criteria.matchIPv6FlowLabel(flowLabel1); + Criterion sameAsMatchFlowLabel1 = Criteria.matchIPv6FlowLabel(flowLabel1); + Criterion matchFlowLabel2 = Criteria.matchIPv6FlowLabel(flowLabel2); + + short icmpv6Type1 = 1; + short icmpv6Type2 = 2; + Criterion matchIcmpv6Type1 = Criteria.matchIcmpv6Type(icmpv6Type1); + Criterion sameAsMatchIcmpv6Type1 = Criteria.matchIcmpv6Type(icmpv6Type1); + Criterion matchIcmpv6Type2 = Criteria.matchIcmpv6Type(icmpv6Type2); + + short icmpv6Code1 = 1; + short icmpv6Code2 = 2; + Criterion matchIcmpv6Code1 = Criteria.matchIcmpv6Code(icmpv6Code1); + Criterion sameAsMatchIcmpv6Code1 = Criteria.matchIcmpv6Code(icmpv6Code1); + Criterion matchIcmpv6Code2 = Criteria.matchIcmpv6Code(icmpv6Code2); + + private static final String IPV6_ADDR1 = "fe80::1"; + private static final String IPV6_ADDR2 = "fe80::2"; + private Ip6Address ip6TargetAddress1 = Ip6Address.valueOf(IPV6_ADDR1); + private Ip6Address ip6TargetAddress2 = Ip6Address.valueOf(IPV6_ADDR2); + Criterion matchIpv6TargetAddr1 = + Criteria.matchIPv6NDTargetAddress(ip6TargetAddress1); + Criterion sameAsMatchIpv6TargetAddr1 = + Criteria.matchIPv6NDTargetAddress(ip6TargetAddress1); + Criterion matchIpv6TargetAddr2 = + Criteria.matchIPv6NDTargetAddress(ip6TargetAddress2); + + private static final String LL_MAC1 = "00:00:00:00:00:01"; + private static final String LL_MAC2 = "00:00:00:00:00:02"; + private MacAddress llMac1 = MacAddress.valueOf(LL_MAC1); + private MacAddress llMac2 = MacAddress.valueOf(LL_MAC2); + Criterion matchSrcLlAddr1 = + Criteria.matchIPv6NDSourceLinkLayerAddress(llMac1); + Criterion sameAsMatchSrcLlAddr1 = + Criteria.matchIPv6NDSourceLinkLayerAddress(llMac1); + Criterion matchSrcLlAddr2 = + Criteria.matchIPv6NDSourceLinkLayerAddress(llMac2); + Criterion matchTargetLlAddr1 = + Criteria.matchIPv6NDTargetLinkLayerAddress(llMac1); + Criterion sameAsMatchTargetLlAddr1 = + Criteria.matchIPv6NDTargetLinkLayerAddress(llMac1); + Criterion matchTargetLlAddr2 = + Criteria.matchIPv6NDTargetLinkLayerAddress(llMac2); + + MplsLabel mpls1 = MplsLabel.mplsLabel(1); + MplsLabel mpls2 = MplsLabel.mplsLabel(2); + Criterion matchMpls1 = Criteria.matchMplsLabel(mpls1); + Criterion sameAsMatchMpls1 = Criteria.matchMplsLabel(mpls1); + Criterion matchMpls2 = Criteria.matchMplsLabel(mpls2); + + long tunnelId1 = 1; + long tunnelId2 = 2; + Criterion matchTunnelId1 = Criteria.matchTunnelId(tunnelId1); + Criterion sameAsMatchTunnelId1 = Criteria.matchTunnelId(tunnelId1); + Criterion matchTunnelId2 = Criteria.matchTunnelId(tunnelId2); + + int ipv6ExthdrFlags1 = + Criterion.IPv6ExthdrFlags.NONEXT.getValue() | + Criterion.IPv6ExthdrFlags.ESP.getValue() | + Criterion.IPv6ExthdrFlags.AUTH.getValue() | + Criterion.IPv6ExthdrFlags.DEST.getValue() | + Criterion.IPv6ExthdrFlags.FRAG.getValue() | + Criterion.IPv6ExthdrFlags.ROUTER.getValue() | + Criterion.IPv6ExthdrFlags.HOP.getValue() | + Criterion.IPv6ExthdrFlags.UNREP.getValue(); + int ipv6ExthdrFlags2 = ipv6ExthdrFlags1 | + Criterion.IPv6ExthdrFlags.UNSEQ.getValue(); + Criterion matchIpv6ExthdrFlags1 = + Criteria.matchIPv6ExthdrFlags(ipv6ExthdrFlags1); + Criterion sameAsMatchIpv6ExthdrFlags1 = + Criteria.matchIPv6ExthdrFlags(ipv6ExthdrFlags1); + 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); + + Criterion matchIndexedLambda1 = Criteria.matchLambda(Lambda.indexedLambda(1)); + 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 = + Criteria.matchLambda(Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, 4, 8)); + Criterion matchOchSignal2 = + Criteria.matchLambda(Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_50GHZ, 4, 8)); + + /** + * Checks that a Criterion object has the proper type, and then converts + * it to the proper type. + * + * @param criterion Criterion object to convert + * @param type Enumerated type value for the Criterion class + * @param clazz Desired Criterion class + * @param The type the caller wants returned + * @return converted object + */ + @SuppressWarnings("unchecked") + private T checkAndConvert(Criterion criterion, Criterion.Type type, Class clazz) { + assertThat(criterion, is(notNullValue())); + assertThat(criterion.type(), is(equalTo(type))); + assertThat(criterion, instanceOf(clazz)); + return (T) criterion; + } + + /** + * Check that the Criteria class is a valid utility class. + */ + @Test + public void testCriteriaUtility() { + assertThatClassIsUtility(Criteria.class); + } + + /** + * Check that the Criteria implementations are immutable. + */ + @Test + public void testCriteriaImmutability() { + assertThatClassIsImmutable(PortCriterion.class); + assertThatClassIsImmutable(MetadataCriterion.class); + assertThatClassIsImmutable(EthCriterion.class); + assertThatClassIsImmutable(EthTypeCriterion.class); + assertThatClassIsImmutable(VlanIdCriterion.class); + assertThatClassIsImmutable(VlanPcpCriterion.class); + assertThatClassIsImmutable(IPDscpCriterion.class); + assertThatClassIsImmutable(IPEcnCriterion.class); + assertThatClassIsImmutable(IPProtocolCriterion.class); + assertThatClassIsImmutable(IPCriterion.class); + assertThatClassIsImmutable(TcpPortCriterion.class); + assertThatClassIsImmutable(UdpPortCriterion.class); + assertThatClassIsImmutable(SctpPortCriterion.class); + assertThatClassIsImmutable(IcmpTypeCriterion.class); + assertThatClassIsImmutable(IcmpCodeCriterion.class); + assertThatClassIsImmutable(IPv6FlowLabelCriterion.class); + assertThatClassIsImmutable(Icmpv6TypeCriterion.class); + assertThatClassIsImmutable(Icmpv6CodeCriterion.class); + assertThatClassIsImmutable(IPv6NDTargetAddressCriterion.class); + assertThatClassIsImmutable(IPv6NDLinkLayerAddressCriterion.class); + assertThatClassIsImmutable(MplsCriterion.class); + assertThatClassIsImmutable(IPv6ExthdrFlagsCriterion.class); + assertThatClassIsImmutable(LambdaCriterion.class); + assertThatClassIsImmutable(OpticalSignalTypeCriterion.class); + } + + // PortCriterion class + + /** + * Test the matchInPort method. + */ + @Test + public void testMatchInPortMethod() { + PortNumber p1 = portNumber(1); + Criterion matchInPort = Criteria.matchInPort(p1); + PortCriterion portCriterion = + checkAndConvert(matchInPort, + Criterion.Type.IN_PORT, + PortCriterion.class); + assertThat(portCriterion.port(), is(equalTo(p1))); + } + + /** + * Test the matchInPhyPort method. + */ + @Test + public void testMatchInPhyPortMethod() { + PortNumber p1 = portNumber(1); + Criterion matchInPhyPort = Criteria.matchInPhyPort(p1); + PortCriterion portCriterion = + checkAndConvert(matchInPhyPort, + Criterion.Type.IN_PHY_PORT, + PortCriterion.class); + assertThat(portCriterion.port(), is(equalTo(p1))); + } + + /** + * Test the equals() method of the PortCriterion class. + */ + @Test + public void testPortCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchInPort1, sameAsMatchInPort1) + .addEqualityGroup(matchInPort2) + .testEquals(); + + new EqualsTester() + .addEqualityGroup(matchInPhyPort1, sameAsMatchInPhyPort1) + .addEqualityGroup(matchInPhyPort2) + .testEquals(); + } + + // MetadataCriterion class + + /** + * Test the matchMetadata method. + */ + @Test + public void testMatchMetadataMethod() { + Long metadata = 12L; + Criterion matchMetadata = Criteria.matchMetadata(metadata); + MetadataCriterion metadataCriterion = + checkAndConvert(matchMetadata, + Criterion.Type.METADATA, + MetadataCriterion.class); + assertThat(metadataCriterion.metadata(), is(equalTo(metadata))); + } + + /** + * Test the equals() method of the MetadataCriterion class. + */ + @Test + public void testMetadataCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchMetadata1, sameAsMatchMetadata1) + .addEqualityGroup(matchMetadata2) + .testEquals(); + } + + // EthCriterion class + + /** + * Test the matchEthDst method. + */ + @Test + public void testMatchEthDstMethod() { + Criterion matchEthDst = Criteria.matchEthDst(mac1); + EthCriterion ethCriterion = + checkAndConvert(matchEthDst, + Criterion.Type.ETH_DST, + EthCriterion.class); + assertThat(ethCriterion.mac(), is(equalTo(mac1))); + } + + /** + * Test the matchEthSrc method. + */ + @Test + public void testMatchEthSrcMethod() { + Criterion matchEthSrc = Criteria.matchEthSrc(mac1); + EthCriterion ethCriterion = + checkAndConvert(matchEthSrc, + Criterion.Type.ETH_SRC, + EthCriterion.class); + assertThat(ethCriterion.mac(), is(mac1)); + } + + /** + * Test the equals() method of the EthCriterion class. + */ + @Test + public void testEthCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchEth1, sameAsMatchEth1) + .addEqualityGroup(matchEth2) + .testEquals(); + } + + // EthTypeCriterion class + + /** + * Test the matchEthType method. + */ + @Test + public void testMatchEthTypeMethod() { + EthType ethType = new EthType(12); + Criterion matchEthType = Criteria.matchEthType(new EthType(12)); + EthTypeCriterion ethTypeCriterion = + checkAndConvert(matchEthType, + Criterion.Type.ETH_TYPE, + EthTypeCriterion.class); + assertThat(ethTypeCriterion.ethType(), is(equalTo(ethType))); + } + + /** + * Test the equals() method of the EthTypeCriterion class. + */ + @Test + public void testEthTypeCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchEthType1, sameAsMatchEthType1) + .addEqualityGroup(matchEthType2) + .testEquals(); + } + + // VlanIdCriterion class + + /** + * Test the matchVlanId method. + */ + @Test + public void testMatchVlanIdMethod() { + Criterion matchVlanId = Criteria.matchVlanId(vlanId1); + VlanIdCriterion vlanIdCriterion = + checkAndConvert(matchVlanId, + Criterion.Type.VLAN_VID, + VlanIdCriterion.class); + assertThat(vlanIdCriterion.vlanId(), is(equalTo(vlanId1))); + } + + /** + * Test the equals() method of the VlanIdCriterion class. + */ + @Test + public void testVlanIdCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchVlanId1, sameAsMatchVlanId1) + .addEqualityGroup(matchVlanId2) + .testEquals(); + } + + // VlanPcpCriterion class + + /** + * Test the matchVlanPcp method. + */ + @Test + public void testMatchVlanPcpMethod() { + Criterion matchVlanPcp = Criteria.matchVlanPcp(vlanPcp1); + VlanPcpCriterion vlanPcpCriterion = + checkAndConvert(matchVlanPcp, + Criterion.Type.VLAN_PCP, + VlanPcpCriterion.class); + assertThat(vlanPcpCriterion.priority(), is(equalTo(vlanPcp1))); + } + + /** + * Test the equals() method of the VlanPcpCriterion class. + */ + @Test + public void testVlanPcpCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchVlanPcp1, sameAsMatchVlanPcp1) + .addEqualityGroup(matchVlanPcp2) + .testEquals(); + } + + // IPDscpCriterion class + + /** + * Test the matchIPDscp method. + */ + @Test + public void testMatchIPDscpMethod() { + Criterion matchIPDscp = Criteria.matchIPDscp(ipDscp1); + IPDscpCriterion ipDscpCriterion = + checkAndConvert(matchIPDscp, + Criterion.Type.IP_DSCP, + IPDscpCriterion.class); + assertThat(ipDscpCriterion.ipDscp(), is(equalTo(ipDscp1))); + } + + /** + * Test the equals() method of the IPDscpCriterion class. + */ + @Test + public void testIPDscpCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchIpDscp1, sameAsMatchIpDscp1) + .addEqualityGroup(matchIpDscp2) + .testEquals(); + } + + // IPEcnCriterion class + + /** + * Test the matchIPEcn method. + */ + @Test + public void testMatchIPEcnMethod() { + Criterion matchIPEcn = Criteria.matchIPEcn(ipEcn1); + IPEcnCriterion ipEcnCriterion = + checkAndConvert(matchIPEcn, + Criterion.Type.IP_ECN, + IPEcnCriterion.class); + assertThat(ipEcnCriterion.ipEcn(), is(equalTo(ipEcn1))); + } + + /** + * Test the equals() method of the IPEcnCriterion class. + */ + @Test + public void testIPEcnCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchIpEcn1, sameAsMatchIpEcn1) + .addEqualityGroup(matchIpEcn2) + .testEquals(); + } + + // IpProtocolCriterion class + + /** + * Test the matchIpProtocol method. + */ + @Test + public void testMatchIpProtocolMethod() { + Criterion matchIPProtocol = Criteria.matchIPProtocol(protocol1); + IPProtocolCriterion ipProtocolCriterion = + checkAndConvert(matchIPProtocol, + Criterion.Type.IP_PROTO, + IPProtocolCriterion.class); + assertThat(ipProtocolCriterion.protocol(), is(equalTo(protocol1))); + } + + /** + * Test the equals() method of the IpProtocolCriterion class. + */ + @Test + public void testIpProtocolCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchIpProtocol1, sameAsMatchIpProtocol1) + .addEqualityGroup(matchIpProtocol2) + .testEquals(); + } + + // IPCriterion class + + /** + * Test the matchIPSrc method: IPv4. + */ + @Test + public void testMatchIPSrcMethod() { + Criterion matchIpSrc = Criteria.matchIPSrc(ip1); + IPCriterion ipCriterion = + checkAndConvert(matchIpSrc, + Criterion.Type.IPV4_SRC, + IPCriterion.class); + assertThat(ipCriterion.ip(), is(ip1)); + } + + /** + * Test the matchIPDst method: IPv4. + */ + @Test + public void testMatchIPDstMethod() { + Criterion matchIPDst = Criteria.matchIPDst(ip1); + IPCriterion ipCriterion = + checkAndConvert(matchIPDst, + Criterion.Type.IPV4_DST, + IPCriterion.class); + assertThat(ipCriterion.ip(), is(equalTo(ip1))); + } + + /** + * Test the matchIPSrc method: IPv6. + */ + @Test + public void testMatchIPv6SrcMethod() { + Criterion matchIpv6Src = Criteria.matchIPv6Src(ipv61); + IPCriterion ipCriterion = + checkAndConvert(matchIpv6Src, + Criterion.Type.IPV6_SRC, + IPCriterion.class); + assertThat(ipCriterion.ip(), is(ipv61)); + } + + /** + * Test the matchIPDst method: IPv6. + */ + @Test + public void testMatchIPv6DstMethod() { + Criterion matchIPv6Dst = Criteria.matchIPv6Dst(ipv61); + IPCriterion ipCriterion = + checkAndConvert(matchIPv6Dst, + Criterion.Type.IPV6_DST, + IPCriterion.class); + assertThat(ipCriterion.ip(), is(equalTo(ipv61))); + } + + /** + * Test the equals() method of the IpCriterion class. + */ + @Test + public void testIPCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchIp1, sameAsMatchIp1) + .addEqualityGroup(matchIp2) + .testEquals(); + + new EqualsTester() + .addEqualityGroup(matchIpv61, sameAsMatchIpv61) + .addEqualityGroup(matchIpv62) + .testEquals(); + } + + // TcpPortCriterion class + + /** + * Test the matchTcpSrc method. + */ + @Test + public void testMatchTcpSrcMethod() { + Criterion matchTcpSrc = Criteria.matchTcpSrc(tpPort1); + TcpPortCriterion tcpPortCriterion = + checkAndConvert(matchTcpSrc, + Criterion.Type.TCP_SRC, + TcpPortCriterion.class); + assertThat(tcpPortCriterion.tcpPort(), is(equalTo(tpPort1))); + } + + /** + * Test the matchTcpDst method. + */ + @Test + public void testMatchTcpDstMethod() { + Criterion matchTcpDst = Criteria.matchTcpDst(tpPort1); + TcpPortCriterion tcpPortCriterion = + checkAndConvert(matchTcpDst, + Criterion.Type.TCP_DST, + TcpPortCriterion.class); + assertThat(tcpPortCriterion.tcpPort(), is(equalTo(tpPort1))); + } + + /** + * Test the equals() method of the TcpPortCriterion class. + */ + @Test + public void testTcpPortCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchTcpPort1, sameAsMatchTcpPort1) + .addEqualityGroup(matchTcpPort2) + .testEquals(); + } + + // UdpPortCriterion class + + /** + * Test the matchUdpSrc method. + */ + @Test + public void testMatchUdpSrcMethod() { + Criterion matchUdpSrc = Criteria.matchUdpSrc(tpPort1); + UdpPortCriterion udpPortCriterion = + checkAndConvert(matchUdpSrc, + Criterion.Type.UDP_SRC, + UdpPortCriterion.class); + assertThat(udpPortCriterion.udpPort(), is(equalTo(tpPort1))); + } + + /** + * Test the matchUdpDst method. + */ + @Test + public void testMatchUdpDstMethod() { + Criterion matchUdpDst = Criteria.matchUdpDst(tpPort1); + UdpPortCriterion udpPortCriterion = + checkAndConvert(matchUdpDst, + Criterion.Type.UDP_DST, + UdpPortCriterion.class); + assertThat(udpPortCriterion.udpPort(), is(equalTo(tpPort1))); + } + + /** + * Test the equals() method of the UdpPortCriterion class. + */ + @Test + public void testUdpPortCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchUdpPort1, sameAsMatchUdpPort1) + .addEqualityGroup(matchUdpPort2) + .testEquals(); + } + + // SctpPortCriterion class + + /** + * Test the matchSctpSrc method. + */ + @Test + public void testMatchSctpSrcMethod() { + Criterion matchSctpSrc = Criteria.matchSctpSrc(tpPort1); + SctpPortCriterion sctpPortCriterion = + checkAndConvert(matchSctpSrc, + Criterion.Type.SCTP_SRC, + SctpPortCriterion.class); + assertThat(sctpPortCriterion.sctpPort(), is(equalTo(tpPort1))); + } + + /** + * Test the matchSctpDst method. + */ + @Test + public void testMatchSctpDstMethod() { + Criterion matchSctpDst = Criteria.matchSctpDst(tpPort1); + SctpPortCriterion sctpPortCriterion = + checkAndConvert(matchSctpDst, + Criterion.Type.SCTP_DST, + SctpPortCriterion.class); + assertThat(sctpPortCriterion.sctpPort(), is(equalTo(tpPort1))); + } + + /** + * Test the equals() method of the SctpPortCriterion class. + */ + @Test + public void testSctpPortCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchSctpPort1, sameAsMatchSctpPort1) + .addEqualityGroup(matchSctpPort2) + .testEquals(); + } + + // IcmpTypeCriterion class + + /** + * Test the matchIcmpType method. + */ + @Test + public void testMatchIcmpTypeMethod() { + short icmpType = 12; + Criterion matchIcmpType = Criteria.matchIcmpType(icmpType); + IcmpTypeCriterion icmpTypeCriterion = + checkAndConvert(matchIcmpType, + Criterion.Type.ICMPV4_TYPE, + IcmpTypeCriterion.class); + assertThat(icmpTypeCriterion.icmpType(), is(equalTo(icmpType))); + } + + /** + * Test the equals() method of the IcmpTypeCriterion class. + */ + @Test + public void testIcmpTypeCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchIcmpType1, sameAsMatchIcmpType1) + .addEqualityGroup(matchIcmpType2) + .testEquals(); + } + + // IcmpCodeCriterion class + + /** + * Test the matchIcmpCode method. + */ + @Test + public void testMatchIcmpCodeMethod() { + short icmpCode = 12; + Criterion matchIcmpCode = Criteria.matchIcmpCode(icmpCode); + IcmpCodeCriterion icmpCodeCriterion = + checkAndConvert(matchIcmpCode, + Criterion.Type.ICMPV4_CODE, + IcmpCodeCriterion.class); + assertThat(icmpCodeCriterion.icmpCode(), is(equalTo(icmpCode))); + } + + /** + * Test the equals() method of the IcmpCodeCriterion class. + */ + @Test + public void testIcmpCodeCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchIcmpCode1, sameAsMatchIcmpCode1) + .addEqualityGroup(matchIcmpCode2) + .testEquals(); + } + + // IPv6FlowLabelCriterion class + + /** + * Test the matchIPv6FlowLabel method. + */ + @Test + public void testMatchIPv6FlowLabelMethod() { + int flowLabel = 12; + Criterion matchFlowLabel = Criteria.matchIPv6FlowLabel(flowLabel); + IPv6FlowLabelCriterion flowLabelCriterion = + checkAndConvert(matchFlowLabel, + Criterion.Type.IPV6_FLABEL, + IPv6FlowLabelCriterion.class); + assertThat(flowLabelCriterion.flowLabel(), is(equalTo(flowLabel))); + } + + /** + * Test the equals() method of the IPv6FlowLabelCriterion class. + */ + @Test + public void testIPv6FlowLabelCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchFlowLabel1, sameAsMatchFlowLabel1) + .addEqualityGroup(matchFlowLabel2) + .testEquals(); + } + + // Icmpv6TypeCriterion class + + /** + * Test the matchIcmpv6Type method. + */ + @Test + public void testMatchIcmpv6TypeMethod() { + short icmpv6Type = 12; + Criterion matchIcmpv6Type = Criteria.matchIcmpv6Type(icmpv6Type); + Icmpv6TypeCriterion icmpv6TypeCriterion = + checkAndConvert(matchIcmpv6Type, + Criterion.Type.ICMPV6_TYPE, + Icmpv6TypeCriterion.class); + assertThat(icmpv6TypeCriterion.icmpv6Type(), is(equalTo(icmpv6Type))); + } + + /** + * Test the equals() method of the Icmpv6TypeCriterion class. + */ + @Test + public void testIcmpv6TypeCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchIcmpv6Type1, sameAsMatchIcmpv6Type1) + .addEqualityGroup(matchIcmpv6Type2) + .testEquals(); + } + + // Icmpv6CodeCriterion class + + /** + * Test the matchIcmpv6Code method. + */ + @Test + public void testMatchIcmpv6CodeMethod() { + short icmpv6Code = 12; + Criterion matchIcmpv6Code = Criteria.matchIcmpv6Code(icmpv6Code); + Icmpv6CodeCriterion icmpv6CodeCriterion = + checkAndConvert(matchIcmpv6Code, + Criterion.Type.ICMPV6_CODE, + Icmpv6CodeCriterion.class); + assertThat(icmpv6CodeCriterion.icmpv6Code(), is(equalTo(icmpv6Code))); + } + + /** + * Test the equals() method of the Icmpv6CodeCriterion class. + */ + @Test + public void testIcmpv6CodeCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchIcmpv6Code1, sameAsMatchIcmpv6Code1) + .addEqualityGroup(matchIcmpv6Code2) + .testEquals(); + } + + // IPv6NDTargetAddressCriterion class + + /** + * Test the matchIPv6NDTargetAddress method. + */ + @Test + public void testMatchIPv6NDTargetAddressMethod() { + Criterion matchTargetAddress = + Criteria.matchIPv6NDTargetAddress(ip6TargetAddress1); + IPv6NDTargetAddressCriterion targetAddressCriterion = + checkAndConvert(matchTargetAddress, + Criterion.Type.IPV6_ND_TARGET, + IPv6NDTargetAddressCriterion.class); + assertThat(targetAddressCriterion.targetAddress(), + is(ip6TargetAddress1)); + } + + /** + * Test the equals() method of the IPv6NDTargetAddressCriterion class. + */ + @Test + public void testIPv6NDTargetAddressCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchIpv6TargetAddr1, + sameAsMatchIpv6TargetAddr1) + .addEqualityGroup(matchIpv6TargetAddr2) + .testEquals(); + } + + // IPv6NDLinkLayerAddressCriterion class + + /** + * Test the matchIPv6NDSourceLinkLayerAddress method. + */ + @Test + public void testMatchIPv6NDSourceLinkLayerAddressMethod() { + Criterion matchSrcLlAddr = + Criteria.matchIPv6NDSourceLinkLayerAddress(llMac1); + IPv6NDLinkLayerAddressCriterion srcLlCriterion = + checkAndConvert(matchSrcLlAddr, + Criterion.Type.IPV6_ND_SLL, + IPv6NDLinkLayerAddressCriterion.class); + assertThat(srcLlCriterion.mac(), is(equalTo(llMac1))); + } + + /** + * Test the matchIPv6NDTargetLinkLayerAddress method. + */ + @Test + public void testMatchIPv6NDTargetLinkLayerAddressMethod() { + Criterion matchTargetLlAddr = + Criteria.matchIPv6NDTargetLinkLayerAddress(llMac1); + IPv6NDLinkLayerAddressCriterion targetLlCriterion = + checkAndConvert(matchTargetLlAddr, + Criterion.Type.IPV6_ND_TLL, + IPv6NDLinkLayerAddressCriterion.class); + assertThat(targetLlCriterion.mac(), is(equalTo(llMac1))); + } + + /** + * Test the equals() method of the IPv6NDLinkLayerAddressCriterion class. + */ + @Test + public void testIPv6NDLinkLayerAddressCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchSrcLlAddr1, sameAsMatchSrcLlAddr1) + .addEqualityGroup(matchSrcLlAddr2) + .testEquals(); + + new EqualsTester() + .addEqualityGroup(matchTargetLlAddr1, sameAsMatchTargetLlAddr1) + .addEqualityGroup(matchTargetLlAddr2) + .testEquals(); + } + + // MplsCriterion class + + /** + * Test the matchMplsLabel method. + */ + @Test + public void testMatchMplsLabelMethod() { + Criterion matchMplsLabel = Criteria.matchMplsLabel(mpls1); + MplsCriterion mplsCriterion = + checkAndConvert(matchMplsLabel, + Criterion.Type.MPLS_LABEL, + MplsCriterion.class); + assertThat(mplsCriterion.label(), is(equalTo(mpls1))); + } + + /** + * Test the equals() method of the MplsCriterion class. + */ + @Test + public void testMplsCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchMpls1, sameAsMatchMpls1) + .addEqualityGroup(matchMpls2) + .testEquals(); + } + + // TunnelIdCriterion class + + /** + * Test the matchTunnelId method. + */ + @Test + public void testMatchTunnelIdMethod() { + Criterion matchTunnelId = Criteria.matchTunnelId(tunnelId1); + TunnelIdCriterion tunnelIdCriterion = + checkAndConvert(matchTunnelId, + Criterion.Type.TUNNEL_ID, + TunnelIdCriterion.class); + assertThat(tunnelIdCriterion.tunnelId(), is(equalTo(tunnelId1))); + + } + + /** + * Test the equals() method of the TunnelIdCriterion class. + */ + @Test + public void testTunnelIdCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchTunnelId1, sameAsMatchTunnelId1) + .addEqualityGroup(matchTunnelId2) + .testEquals(); + } + + // IPv6ExthdrFlagsCriterion class + + /** + * Test the matchIPv6ExthdrFlags method. + */ + @Test + public void testMatchIPv6ExthdrFlagsMethod() { + Criterion matchExthdrFlags = + Criteria.matchIPv6ExthdrFlags(ipv6ExthdrFlags1); + IPv6ExthdrFlagsCriterion exthdrFlagsCriterion = + checkAndConvert(matchExthdrFlags, + Criterion.Type.IPV6_EXTHDR, + IPv6ExthdrFlagsCriterion.class); + assertThat(exthdrFlagsCriterion.exthdrFlags(), + is(equalTo(ipv6ExthdrFlags1))); + } + + /** + * Test the equals() method of the IPv6ExthdrFlagsCriterion class. + */ + @Test + public void testIPv6ExthdrFlagsCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchIpv6ExthdrFlags1, + sameAsMatchIpv6ExthdrFlags1) + .addEqualityGroup(matchIpv6ExthdrFlags2) + .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() + .addEqualityGroup(matchIndexedLambda1, sameAsMatchIndexedLambda1) + .addEqualityGroup(matchIndexedLambda2) + .testEquals(); + } + + @Test + public void testOchSignalCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchOchSignal1, sameAsMatchOchSignal1) + .addEqualityGroup(matchOchSignal2) + .testEquals(); + } + + /** + * Test the equals() method of the OchSignalTypeCriterion class. + */ + @Test + public void testOchSignalTypeCriterionEquals() { + new EqualsTester() + .addEqualityGroup(matchOchSignalType1, sameAsMatchOchSignalType1) + .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/flow/instructions/InstructionsTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/instructions/InstructionsTest.java new file mode 100644 index 00000000..410349b5 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flow/instructions/InstructionsTest.java @@ -0,0 +1,725 @@ +/* + * Copyright 2014-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.instructions; + +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.TpPort; +import org.onlab.packet.VlanId; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.GridType; +import org.onosproject.net.IndexedLambda; +import org.onosproject.net.Lambda; +import org.onosproject.net.PortNumber; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onlab.junit.UtilityClassChecker.assertThatClassIsUtility; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Unit tests for the Instructions class. + */ +public class InstructionsTest { + + /** + * Checks that a Criterion object has the proper type, and then converts + * it to the proper type. + * + * @param instruction Instruction object to convert + * @param type Enumerated type value for the Criterion class + * @param clazz Desired Criterion class + * @param The type the caller wants returned + * @return converted object + */ + @SuppressWarnings("unchecked") + private T checkAndConvert(Instruction instruction, Instruction.Type type, Class clazz) { + assertThat(instruction, is(notNullValue())); + assertThat(instruction.type(), is(equalTo(type))); + assertThat(instruction, instanceOf(clazz)); + return (T) instruction; + } + + /** + * Checks the equals() and toString() methods of a Criterion class. + * + * @param c1 first object to compare + * @param c1match object that should be equal to the first + * @param c2 object that should be not equal to the first + * @param type of the arguments + */ + private void checkEqualsAndToString(T c1, T c1match, + T c2) { + + new EqualsTester() + .addEqualityGroup(c1, c1match) + .addEqualityGroup(c2) + .testEquals(); + } + + /** + * Checks that Instructions is a proper utility class. + */ + @Test + public void testInstructionsUtilityClass() { + assertThatClassIsUtility(Instructions.class); + } + + /** + * Checks that the Instruction class implementations are immutable. + */ + @Test + public void testImmutabilityOfInstructions() { + assertThatClassIsImmutable(Instructions.DropInstruction.class); + assertThatClassIsImmutable(Instructions.OutputInstruction.class); + assertThatClassIsImmutable(L0ModificationInstruction.ModLambdaInstruction.class); + assertThatClassIsImmutable(L0ModificationInstruction.ModOchSignalInstruction.class); + assertThatClassIsImmutable(L2ModificationInstruction.ModEtherInstruction.class); + assertThatClassIsImmutable(L2ModificationInstruction.ModVlanIdInstruction.class); + assertThatClassIsImmutable(L2ModificationInstruction.ModVlanPcpInstruction.class); + assertThatClassIsImmutable(L3ModificationInstruction.ModIPInstruction.class); + assertThatClassIsImmutable(L3ModificationInstruction.ModIPv6FlowLabelInstruction.class); + assertThatClassIsImmutable(L2ModificationInstruction.ModMplsLabelInstruction.class); + assertThatClassIsImmutable(L2ModificationInstruction.PushHeaderInstructions.class); + } + + // DropInstruction + + private final Instructions.DropInstruction drop1 = Instructions.createDrop(); + private final Instructions.DropInstruction drop2 = Instructions.createDrop(); + + /** + * Test the createDrop method. + */ + @Test + public void testCreateDropMethod() { + Instructions.DropInstruction instruction = Instructions.createDrop(); + checkAndConvert(instruction, + Instruction.Type.DROP, + Instructions.DropInstruction.class); + } + + /** + * Test the equals() method of the DropInstruction class. + */ + + @Test + public void testDropInstructionEquals() throws Exception { + assertThat(drop1, is(equalTo(drop2))); + } + + /** + * Test the hashCode() method of the DropInstruction class. + */ + + @Test + public void testDropInstructionHashCode() { + assertThat(drop1.hashCode(), is(equalTo(drop2.hashCode()))); + } + + // OutputInstruction + + private final PortNumber port1 = portNumber(1); + private final PortNumber port2 = portNumber(2); + private final Instructions.OutputInstruction output1 = Instructions.createOutput(port1); + private final Instructions.OutputInstruction sameAsOutput1 = Instructions.createOutput(port1); + private final Instructions.OutputInstruction output2 = Instructions.createOutput(port2); + + /** + * Test the createOutput method. + */ + @Test + public void testCreateOutputMethod() { + final Instruction instruction = Instructions.createOutput(port2); + final Instructions.OutputInstruction outputInstruction = + checkAndConvert(instruction, + Instruction.Type.OUTPUT, + Instructions.OutputInstruction.class); + assertThat(outputInstruction.port(), is(equalTo(port2))); + } + + + /** + * Test the equals() method of the OutputInstruction class. + */ + + @Test + public void testOutputInstructionEquals() throws Exception { + checkEqualsAndToString(output1, sameAsOutput1, output2); + } + + /** + * Test the hashCode() method of the OutputInstruction class. + */ + + @Test + public void testOutputInstructionHashCode() { + assertThat(output1.hashCode(), is(equalTo(sameAsOutput1.hashCode()))); + assertThat(output1.hashCode(), is(not(equalTo(output2.hashCode())))); + } + + // ModLambdaInstruction + + private final IndexedLambda lambda1 = new IndexedLambda(1); + private final IndexedLambda lambda2 = new IndexedLambda(2); + private final Instruction lambdaInstruction1 = Instructions.modL0Lambda(lambda1); + private final Instruction sameAsLambdaInstruction1 = Instructions.modL0Lambda(lambda1); + private final Instruction lambdaInstruction2 = Instructions.modL0Lambda(lambda2); + + /** + * Test the modL0Lambda method. + */ + @Test + public void testCreateLambdaMethod() { + final Instruction instruction = Instructions.modL0Lambda(lambda1); + final L0ModificationInstruction.ModLambdaInstruction lambdaInstruction = + checkAndConvert(instruction, + Instruction.Type.L0MODIFICATION, + L0ModificationInstruction.ModLambdaInstruction.class); + assertThat(lambdaInstruction.lambda(), is(equalTo((short) lambda1.index()))); + } + + /** + * Test the equals() method of the ModLambdaInstruction class. + */ + + @Test + public void testModLambdaInstructionEquals() throws Exception { + checkEqualsAndToString(lambdaInstruction1, + sameAsLambdaInstruction1, + lambdaInstruction2); + } + + /** + * Test the hashCode() method of the ModLambdaInstruction class. + */ + + @Test + public void testModLambdaInstructionHashCode() { + assertThat(lambdaInstruction1.hashCode(), + is(equalTo(sameAsLambdaInstruction1.hashCode()))); + assertThat(lambdaInstruction1.hashCode(), + is(not(equalTo(lambdaInstruction2.hashCode())))); + } + + private final Lambda och1 = Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, 4, 8); + private final Lambda och2 = Lambda.ochSignal(GridType.CWDM, ChannelSpacing.CHL_100GHZ, 4, 8); + private final Instruction ochInstruction1 = Instructions.modL0Lambda(och1); + private final Instruction sameAsOchInstruction1 = Instructions.modL0Lambda(och1); + private final Instruction ochInstruction2 = Instructions.modL0Lambda(och2); + + /** + * Test the modL0Lambda(). + */ + @Test + public void testModL0LambdaMethod() { + Instruction instruction = Instructions.modL0Lambda(och1); + L0ModificationInstruction.ModOchSignalInstruction ochInstruction = + checkAndConvert(instruction, Instruction.Type.L0MODIFICATION, + L0ModificationInstruction.ModOchSignalInstruction.class); + assertThat(ochInstruction.lambda(), is(och1)); + } + + /** + * Test the equals() method of the ModOchSignalInstruction class. + */ + @Test + public void testModOchSignalInstructionEquals() { + checkEqualsAndToString(ochInstruction1, sameAsOchInstruction1, ochInstruction2); + } + + /** + * Test the hashCode() method of the ModOchSignalInstruction class. + */ + @Test + public void testModOchSignalInstructionHashCode() { + assertThat(ochInstruction1.hashCode(), is(sameAsOchInstruction1.hashCode())); + assertThat(ochInstruction1.hashCode(), is(not(ochInstruction2.hashCode()))); + } + + // ModEtherInstruction + + private static final String MAC1 = "00:00:00:00:00:01"; + private static final String MAC2 = "00:00:00:00:00:02"; + private final MacAddress mac1 = MacAddress.valueOf(MAC1); + private final MacAddress mac2 = MacAddress.valueOf(MAC2); + private final Instruction modEtherInstruction1 = Instructions.modL2Src(mac1); + private final Instruction sameAsModEtherInstruction1 = Instructions.modL2Src(mac1); + private final Instruction modEtherInstruction2 = Instructions.modL2Src(mac2); + + /** + * Test the modL2Src method. + */ + @Test + public void testModL2SrcMethod() { + final Instruction instruction = Instructions.modL2Src(mac1); + final L2ModificationInstruction.ModEtherInstruction modEtherInstruction = + checkAndConvert(instruction, + Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.ModEtherInstruction.class); + assertThat(modEtherInstruction.mac(), is(equalTo(mac1))); + assertThat(modEtherInstruction.subtype(), + is(equalTo(L2ModificationInstruction.L2SubType.ETH_SRC))); + } + + /** + * Test the modL2Dst method. + */ + @Test + public void testModL2DstMethod() { + final Instruction instruction = Instructions.modL2Dst(mac1); + final L2ModificationInstruction.ModEtherInstruction modEtherInstruction = + checkAndConvert(instruction, + Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.ModEtherInstruction.class); + assertThat(modEtherInstruction.mac(), is(equalTo(mac1))); + assertThat(modEtherInstruction.subtype(), + is(equalTo(L2ModificationInstruction.L2SubType.ETH_DST))); + } + + /** + * Test the equals() method of the ModEtherInstruction class. + */ + + @Test + public void testModEtherInstructionEquals() throws Exception { + checkEqualsAndToString(modEtherInstruction1, + sameAsModEtherInstruction1, + modEtherInstruction2); + } + + /** + * Test the hashCode() method of the ModEtherInstruction class. + */ + + @Test + public void testModEtherInstructionHashCode() { + assertThat(modEtherInstruction1.hashCode(), + is(equalTo(sameAsModEtherInstruction1.hashCode()))); + assertThat(modEtherInstruction1.hashCode(), + is(not(equalTo(modEtherInstruction2.hashCode())))); + } + + + // ModVlanIdInstruction + + private final short vlan1 = 1; + private final short vlan2 = 2; + private final VlanId vlanId1 = VlanId.vlanId(vlan1); + private final VlanId vlanId2 = VlanId.vlanId(vlan2); + private final Instruction modVlanId1 = Instructions.modVlanId(vlanId1); + private final Instruction sameAsModVlanId1 = Instructions.modVlanId(vlanId1); + private final Instruction modVlanId2 = Instructions.modVlanId(vlanId2); + + /** + * Test the modVlanId method. + */ + @Test + public void testModVlanIdMethod() { + final Instruction instruction = Instructions.modVlanId(vlanId1); + final L2ModificationInstruction.ModVlanIdInstruction modEtherInstruction = + checkAndConvert(instruction, + Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.ModVlanIdInstruction.class); + assertThat(modEtherInstruction.vlanId(), is(equalTo(vlanId1))); + assertThat(modEtherInstruction.subtype(), + is(equalTo(L2ModificationInstruction.L2SubType.VLAN_ID))); + } + + /** + * Test the equals() method of the ModVlanIdInstruction class. + */ + + @Test + public void testModVlanIdInstructionEquals() throws Exception { + checkEqualsAndToString(modVlanId1, + sameAsModVlanId1, + modVlanId2); + } + + /** + * Test the hashCode() method of the ModEtherInstruction class. + */ + + @Test + public void testModVlanIdInstructionHashCode() { + assertThat(modVlanId1.hashCode(), + is(equalTo(sameAsModVlanId1.hashCode()))); + assertThat(modVlanId1.hashCode(), + is(not(equalTo(modVlanId2.hashCode())))); + } + + + // ModVlanPcpInstruction + + private final byte vlanPcp1 = 1; + private final byte vlanPcp2 = 2; + private final Instruction modVlanPcp1 = Instructions.modVlanPcp(vlanPcp1); + private final Instruction sameAsModVlanPcp1 = Instructions.modVlanPcp(vlanPcp1); + private final Instruction modVlanPcp2 = Instructions.modVlanPcp(vlanPcp2); + + /** + * Test the modVlanPcp method. + */ + @Test + public void testModVlanPcpMethod() { + final Instruction instruction = Instructions.modVlanPcp(vlanPcp1); + final L2ModificationInstruction.ModVlanPcpInstruction modEtherInstruction = + checkAndConvert(instruction, + Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.ModVlanPcpInstruction.class); + assertThat(modEtherInstruction.vlanPcp(), is(equalTo(vlanPcp1))); + assertThat(modEtherInstruction.subtype(), + is(equalTo(L2ModificationInstruction.L2SubType.VLAN_PCP))); + } + + /** + * Test the equals() method of the ModVlanPcpInstruction class. + */ + + @Test + public void testModVlanPcpInstructionEquals() throws Exception { + checkEqualsAndToString(modVlanPcp1, + sameAsModVlanPcp1, + modVlanPcp2); + } + + /** + * Test the hashCode() method of the ModEtherInstruction class. + */ + + @Test + public void testModVlanPcpInstructionHashCode() { + assertThat(modVlanPcp1.hashCode(), + is(equalTo(sameAsModVlanPcp1.hashCode()))); + assertThat(modVlanPcp1.hashCode(), + is(not(equalTo(modVlanPcp2.hashCode())))); + } + + // ModIPInstruction + + private static final String IP41 = "1.2.3.4"; + private static final String IP42 = "5.6.7.8"; + private IpAddress ip41 = IpAddress.valueOf(IP41); + private IpAddress ip42 = IpAddress.valueOf(IP42); + private final Instruction modIPInstruction1 = Instructions.modL3Src(ip41); + private final Instruction sameAsModIPInstruction1 = Instructions.modL3Src(ip41); + private final Instruction modIPInstruction2 = Instructions.modL3Src(ip42); + + private static final String IP61 = "1111::2222"; + private static final String IP62 = "3333::4444"; + private IpAddress ip61 = IpAddress.valueOf(IP61); + private IpAddress ip62 = IpAddress.valueOf(IP62); + private final Instruction modIPv6Instruction1 = + Instructions.modL3IPv6Src(ip61); + private final Instruction sameAsModIPv6Instruction1 = + Instructions.modL3IPv6Src(ip61); + private final Instruction modIPv6Instruction2 = + Instructions.modL3IPv6Src(ip62); + + /** + * Test the modL3Src method. + */ + @Test + public void testModL3SrcMethod() { + final Instruction instruction = Instructions.modL3Src(ip41); + final L3ModificationInstruction.ModIPInstruction modIPInstruction = + checkAndConvert(instruction, + Instruction.Type.L3MODIFICATION, + L3ModificationInstruction.ModIPInstruction.class); + assertThat(modIPInstruction.ip(), is(equalTo(ip41))); + assertThat(modIPInstruction.subtype(), + is(equalTo(L3ModificationInstruction.L3SubType.IPV4_SRC))); + } + + /** + * Test the modL3Dst method. + */ + @Test + public void testModL3DstMethod() { + final Instruction instruction = Instructions.modL3Dst(ip41); + final L3ModificationInstruction.ModIPInstruction modIPInstruction = + checkAndConvert(instruction, + Instruction.Type.L3MODIFICATION, + L3ModificationInstruction.ModIPInstruction.class); + assertThat(modIPInstruction.ip(), is(equalTo(ip41))); + assertThat(modIPInstruction.subtype(), + is(equalTo(L3ModificationInstruction.L3SubType.IPV4_DST))); + } + + /** + * Test the modL3IPv6Src method. + */ + @Test + public void testModL3IPv6SrcMethod() { + final Instruction instruction = Instructions.modL3IPv6Src(ip61); + final L3ModificationInstruction.ModIPInstruction modIPInstruction = + checkAndConvert(instruction, + Instruction.Type.L3MODIFICATION, + L3ModificationInstruction.ModIPInstruction.class); + assertThat(modIPInstruction.ip(), is(equalTo(ip61))); + assertThat(modIPInstruction.subtype(), + is(equalTo(L3ModificationInstruction.L3SubType.IPV6_SRC))); + } + + /** + * Test the modL3IPv6Dst method. + */ + @Test + public void testModL3IPv6DstMethod() { + final Instruction instruction = Instructions.modL3IPv6Dst(ip61); + final L3ModificationInstruction.ModIPInstruction modIPInstruction = + checkAndConvert(instruction, + Instruction.Type.L3MODIFICATION, + L3ModificationInstruction.ModIPInstruction.class); + assertThat(modIPInstruction.ip(), is(equalTo(ip61))); + assertThat(modIPInstruction.subtype(), + is(equalTo(L3ModificationInstruction.L3SubType.IPV6_DST))); + } + + /** + * Test the equals() method of the ModIPInstruction class. + */ + @Test + public void testModIPInstructionEquals() throws Exception { + checkEqualsAndToString(modIPInstruction1, + sameAsModIPInstruction1, + modIPInstruction2); + } + + /** + * Test the hashCode() method of the ModIPInstruction class. + */ + @Test + public void testModIPInstructionHashCode() { + assertThat(modIPInstruction1.hashCode(), + is(equalTo(sameAsModIPInstruction1.hashCode()))); + assertThat(modIPInstruction1.hashCode(), + is(not(equalTo(modIPInstruction2.hashCode())))); + } + + private final int flowLabel1 = 0x11111; + private final int flowLabel2 = 0x22222; + private final Instruction modIPv6FlowLabelInstruction1 = + Instructions.modL3IPv6FlowLabel(flowLabel1); + private final Instruction sameAsModIPv6FlowLabelInstruction1 = + Instructions.modL3IPv6FlowLabel(flowLabel1); + private final Instruction modIPv6FlowLabelInstruction2 = + Instructions.modL3IPv6FlowLabel(flowLabel2); + + /** + * Test the modL3IPv6FlowLabel method. + */ + @Test + public void testModL3IPv6FlowLabelMethod() { + final Instruction instruction = + Instructions.modL3IPv6FlowLabel(flowLabel1); + final L3ModificationInstruction.ModIPv6FlowLabelInstruction + modIPv6FlowLabelInstruction = + checkAndConvert(instruction, + Instruction.Type.L3MODIFICATION, + L3ModificationInstruction.ModIPv6FlowLabelInstruction.class); + assertThat(modIPv6FlowLabelInstruction.flowLabel(), + is(equalTo(flowLabel1))); + assertThat(modIPv6FlowLabelInstruction.subtype(), + is(equalTo(L3ModificationInstruction.L3SubType.IPV6_FLABEL))); + } + + /** + * Test the equals() method of the ModIPv6FlowLabelInstruction class. + */ + @Test + public void testModIPv6FlowLabelInstructionEquals() throws Exception { + checkEqualsAndToString(modIPv6FlowLabelInstruction1, + sameAsModIPv6FlowLabelInstruction1, + modIPv6FlowLabelInstruction2); + } + + /** + * Test the hashCode() method of the ModIPv6FlowLabelInstruction class. + */ + @Test + public void testModIPv6FlowLabelInstructionHashCode() { + assertThat(modIPv6FlowLabelInstruction1.hashCode(), + is(equalTo(sameAsModIPv6FlowLabelInstruction1.hashCode()))); + assertThat(modIPv6FlowLabelInstruction1.hashCode(), + is(not(equalTo(modIPv6FlowLabelInstruction2.hashCode())))); + } + + private Instruction modMplsLabelInstruction1 = Instructions.modMplsLabel(MplsLabel.mplsLabel(1)); + private Instruction sameAsModMplsLabelInstruction1 = Instructions.modMplsLabel(MplsLabel.mplsLabel(1)); + private Instruction modMplsLabelInstruction2 = Instructions.modMplsLabel(MplsLabel.mplsLabel(2)); + + /** + * Test the modMplsLabel method. + */ + @Test + public void testModMplsMethod() { + final MplsLabel mplsLabel = MplsLabel.mplsLabel(33); + final Instruction instruction = Instructions.modMplsLabel(mplsLabel); + final L2ModificationInstruction.ModMplsLabelInstruction modMplsLabelInstruction = + checkAndConvert(instruction, + Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.ModMplsLabelInstruction.class); + assertThat(modMplsLabelInstruction.mplsLabel(), is(equalTo(mplsLabel))); + assertThat(modMplsLabelInstruction.subtype(), + is(equalTo(L2ModificationInstruction.L2SubType.MPLS_LABEL))); + } + + /** + * Test the equals(), hashCode and toString() methods of the + * ModMplsLabelInstruction class. + */ + @Test + public void testModMplsLabelInstructionEquals() throws Exception { + checkEqualsAndToString(modMplsLabelInstruction1, + sameAsModMplsLabelInstruction1, + modMplsLabelInstruction2); + } + + // ModTunnelIdInstruction + + private final long tunnelId1 = 1L; + private final long tunnelId2 = 2L; + private final Instruction modTunnelId1 = Instructions.modTunnelId(tunnelId1); + private final Instruction sameAsModTunnelId1 = Instructions.modTunnelId(tunnelId1); + private final Instruction modTunnelId2 = Instructions.modTunnelId(tunnelId2); + + /** + * Test the modTunnelId method. + */ + @Test + public void testModTunnelIdMethod() { + final Instruction instruction = Instructions.modTunnelId(tunnelId1); + final L2ModificationInstruction.ModTunnelIdInstruction modTunnelIdInstruction = + checkAndConvert(instruction, Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.ModTunnelIdInstruction.class); + assertThat(modTunnelIdInstruction.tunnelId(), is(equalTo(tunnelId1))); + assertThat(modTunnelIdInstruction.subtype(), + is(equalTo(L2ModificationInstruction.L2SubType.TUNNEL_ID))); + } + + /*** + * Test the equals() method of the ModTunnelIdInstruction class. + */ + @Test + public void testModTunnelIdInstructionEquals() throws Exception { + checkEqualsAndToString(modTunnelId1, sameAsModTunnelId1, modTunnelId2); + } + + /** + * Test the hashCode() method of the ModTunnelIdInstruction class. + */ + @Test + public void testModTunnelIdInstructionHashCode() { + assertThat(modTunnelId1.hashCode(), is(equalTo(sameAsModTunnelId1.hashCode()))); + assertThat(modTunnelId1.hashCode(), is(not(equalTo(modTunnelId2.hashCode())))); + } + + // ModTransportPortInstruction + + private final TpPort tpPort1 = TpPort.tpPort(1); + private final TpPort tpPort2 = TpPort.tpPort(2); + private final Instruction modTransportPortInstruction1 = Instructions.modTcpSrc(tpPort1); + private final Instruction sameAsModTransportPortInstruction1 = Instructions.modTcpSrc(tpPort1); + private final Instruction modTransportPortInstruction2 = Instructions.modTcpSrc(tpPort2); + + /** + * Test the modTcpSrc() method. + */ + @Test + public void testModTcpSrcMethod() { + final Instruction instruction = Instructions.modTcpSrc(tpPort1); + final L4ModificationInstruction.ModTransportPortInstruction modTransportPortInstruction = + checkAndConvert(instruction, Instruction.Type.L4MODIFICATION, + L4ModificationInstruction.ModTransportPortInstruction.class); + assertThat(modTransportPortInstruction.port(), is(equalTo(tpPort1))); + assertThat(modTransportPortInstruction.subtype(), + is(equalTo(L4ModificationInstruction.L4SubType.TCP_SRC))); + } + + /** + * Test the modTcpDst() method. + */ + @Test + public void testModTcpDstMethod() { + final Instruction instruction = Instructions.modTcpDst(tpPort1); + final L4ModificationInstruction.ModTransportPortInstruction modTransportPortInstruction = + checkAndConvert(instruction, Instruction.Type.L4MODIFICATION, + L4ModificationInstruction.ModTransportPortInstruction.class); + assertThat(modTransportPortInstruction.port(), is(equalTo(tpPort1))); + assertThat(modTransportPortInstruction.subtype(), + is(equalTo(L4ModificationInstruction.L4SubType.TCP_DST))); + } + + /** + * Test the modUdpSrc() method. + */ + @Test + public void testModUdpSrcMethod() { + final Instruction instruction = Instructions.modUdpSrc(tpPort1); + final L4ModificationInstruction.ModTransportPortInstruction modTransportPortInstruction = + checkAndConvert(instruction, Instruction.Type.L4MODIFICATION, + L4ModificationInstruction.ModTransportPortInstruction.class); + assertThat(modTransportPortInstruction.port(), is(equalTo(tpPort1))); + assertThat(modTransportPortInstruction.subtype(), + is(equalTo(L4ModificationInstruction.L4SubType.UDP_SRC))); + } + + /** + * Test the modUdpDst() method. + */ + @Test + public void testModUdpDstMethod() { + final Instruction instruction = Instructions.modUdpDst(tpPort1); + final L4ModificationInstruction.ModTransportPortInstruction modTransportPortInstruction = + checkAndConvert(instruction, Instruction.Type.L4MODIFICATION, + L4ModificationInstruction.ModTransportPortInstruction.class); + assertThat(modTransportPortInstruction.port(), is(equalTo(tpPort1))); + assertThat(modTransportPortInstruction.subtype(), + is(equalTo(L4ModificationInstruction.L4SubType.UDP_DST))); + } + + /** + * Test the equals() method of the ModTransportPortInstruction class. + */ + @Test + public void testModTransportPortInstructionEquals() throws Exception { + checkEqualsAndToString(modTransportPortInstruction1, + sameAsModTransportPortInstruction1, + modTransportPortInstruction2); + } + + /** + * Test the hashCode() method of the ModTransportPortInstruction class. + */ + @Test + public void testModTransportPortInstructionHashCode() { + assertThat(modTransportPortInstruction1.hashCode(), + is(equalTo(sameAsModTransportPortInstruction1.hashCode()))); + assertThat(modTransportPortInstruction1.hashCode(), + is(not(equalTo(modTransportPortInstruction2.hashCode())))); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/flowobjective/ObjectiveTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flowobjective/ObjectiveTest.java new file mode 100644 index 00000000..850582b0 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/flowobjective/ObjectiveTest.java @@ -0,0 +1,313 @@ +/* + * 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.flowobjective; + +import org.junit.Test; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.criteria.Criteria; +import org.onosproject.net.flow.criteria.Criterion; + +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.not; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.net.NetTestTools.APP_ID; +import static org.onosproject.net.flowobjective.FilteringObjective.Type.DENY; +import static org.onosproject.net.flowobjective.ForwardingObjective.Flag.SPECIFIC; +import static org.onosproject.net.flowobjective.NextObjective.Type.HASHED; +import static org.onosproject.net.flowobjective.Objective.Operation.ADD; +import static org.onosproject.net.flowobjective.Objective.Operation.REMOVE; + +/** + * Unit tests for forwarding objective class. + */ +public class ObjectiveTest { + + private final TrafficTreatment treatment = + DefaultTrafficTreatment.emptyTreatment(); + private final TrafficSelector selector = + DefaultTrafficSelector.emptySelector(); + private final Criterion criterion = Criteria.dummy(); + private final Criterion key = Criteria.dummy(); + + /** + * Mock objective context. + */ + private static class MockObjectiveContext implements ObjectiveContext { + @Override + public void onSuccess(Objective objective) { + // stub + } + + @Override + public void onError(Objective objective, ObjectiveError error) { + // stub + } + } + + /** + * Checks immutability of objective classes. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(DefaultFilteringObjective.class); + assertThatClassIsImmutable(DefaultForwardingObjective.class); + assertThatClassIsImmutable(DefaultNextObjective.class); + } + + // Forwarding Objectives + + /** + * Makes a forwarding objective builder with a set of default values. + * + * @return forwarding objective builder + */ + private ForwardingObjective.Builder baseForwardingBuilder() { + return DefaultForwardingObjective.builder() + .withSelector(selector) + .withTreatment(treatment) + .withFlag(SPECIFIC) + .fromApp(APP_ID) + .withPriority(22) + .makeTemporary(5) + .nextStep(33); + } + + /** + * Checks the default values of a forwarding objective object. + * + * @param objective forwarding objective to check + */ + private void checkForwardingBase(ForwardingObjective objective, + Objective.Operation op, + ObjectiveContext expectedContext) { + assertThat(objective.permanent(), is(false)); + assertThat(objective.timeout(), is(5)); + assertThat(objective.selector(), is(selector)); + assertThat(objective.treatment(), is(treatment)); + assertThat(objective.flag(), is(SPECIFIC)); + assertThat(objective.appId(), is(APP_ID)); + assertThat(objective.nextId(), is(33)); + assertThat(objective.id(), is(not(0))); + assertThat(objective.priority(), is(22)); + assertThat(objective.op(), is(op)); + if (objective.context().isPresent()) { + assertThat(objective.context().get(), is(expectedContext)); + } else { + assertThat(expectedContext, nullValue()); + } + } + + /** + * Tests that forwarding objective objects are built correctly using the + * add() method. + */ + @Test + public void testForwardingAdd() { + checkForwardingBase(baseForwardingBuilder().add(), ADD, null); + } + + /** + * Tests that forwarding objective objects are built correctly using the + * add(context) method. + */ + @Test + public void testForwardingAddWithContext() { + ObjectiveContext context = new MockObjectiveContext(); + checkForwardingBase(baseForwardingBuilder().add(context), ADD, context); + } + + /** + * Tests that forwarding objective objects are built correctly using the + * remove() method. + */ + @Test + public void testForwardingRemove() { + checkForwardingBase(baseForwardingBuilder().remove(), REMOVE, null); + } + + /** + * Tests that forwarding objective objects are built correctly using the + * remove(context) method. + */ + @Test + public void testForwardingRemoveWithContext() { + ObjectiveContext context = new MockObjectiveContext(); + checkForwardingBase(baseForwardingBuilder().remove(context), REMOVE, context); + } + + // Filtering objectives + + /** + * Makes a filtering objective builder with a set of default values. + * + * @return filtering objective builder + */ + private FilteringObjective.Builder baseFilteringBuilder() { + return DefaultFilteringObjective.builder() + .withKey(key) + .withPriority(5) + .addCondition(criterion) + .fromApp(APP_ID) + .makeTemporary(2) + .deny(); + } + + /** + * Checks the default values of a filtering objective object. + * + * @param objective filtering objective to check + */ + private void checkFilteringBase(FilteringObjective objective, + Objective.Operation op, + ObjectiveContext expectedContext) { + assertThat(objective.key(), is(key)); + assertThat(objective.conditions(), hasItem(criterion)); + assertThat(objective.permanent(), is(false)); + assertThat(objective.timeout(), is(2)); + assertThat(objective.priority(), is(5)); + assertThat(objective.appId(), is(APP_ID)); + assertThat(objective.type(), is(DENY)); + assertThat(objective.id(), is(not(0))); + assertThat(objective.op(), is(op)); + if (objective.context().isPresent()) { + assertThat(objective.context().get(), is(expectedContext)); + } else { + assertThat(expectedContext, nullValue()); + } + } + + /** + * Tests that forwarding objective objects are built correctly using the + * add() method. + */ + @Test + public void testFilteringAdd() { + checkFilteringBase(baseFilteringBuilder().add(), ADD, null); + } + + /** + * Tests that forwarding objective objects are built correctly using the + * add(context) method. + */ + @Test + public void testFilteringAddWithContext() { + ObjectiveContext context = new MockObjectiveContext(); + checkFilteringBase(baseFilteringBuilder().add(context), ADD, context); + } + + /** + * Tests that forwarding objective objects are built correctly using the + * remove() method. + */ + @Test + public void testFilteringRemove() { + checkFilteringBase(baseFilteringBuilder().remove(), REMOVE, null); + } + + /** + * Tests that forwarding objective objects are built correctly using the + * remove(context) method. + */ + @Test + public void testFilteringRemoveWithContext() { + ObjectiveContext context = new MockObjectiveContext(); + checkFilteringBase(baseFilteringBuilder().remove(context), REMOVE, context); + } + + // Next objectives + + /** + * Makes a next objective builder with a set of default values. + * + * @return next objective builder + */ + private NextObjective.Builder baseNextBuilder() { + return DefaultNextObjective.builder() + .addTreatment(treatment) + .withId(12) + .withType(HASHED) + .makeTemporary(777) + .withPriority(33) + .fromApp(APP_ID); + } + + /** + * Checks the default values of a next objective object. + * + * @param objective next objective to check + */ + private void checkNextBase(NextObjective objective, + Objective.Operation op, + ObjectiveContext expectedContext) { + assertThat(objective.id(), is(12)); + assertThat(objective.appId(), is(APP_ID)); + assertThat(objective.type(), is(HASHED)); + assertThat(objective.next(), hasItem(treatment)); + assertThat(objective.permanent(), is(false)); + assertThat(objective.timeout(), is(0)); + assertThat(objective.priority(), is(0)); + assertThat(objective.op(), is(op)); + if (objective.context().isPresent()) { + assertThat(objective.context().get(), is(expectedContext)); + } else { + assertThat(expectedContext, nullValue()); + } + } + + /** + * Tests that forwarding objective objects are built correctly using the + * add() method. + */ + @Test + public void testNextAdd() { + checkNextBase(baseNextBuilder().add(), ADD, null); + } + + /** + * Tests that forwarding objective objects are built correctly using the + * add(context) method. + */ + @Test + public void testNextAddWithContext() { + ObjectiveContext context = new MockObjectiveContext(); + checkNextBase(baseNextBuilder().add(context), ADD, context); + } + + /** + * Tests that forwarding objective objects are built correctly using the + * remove() method. + */ + @Test + public void testNextRemove() { + checkNextBase(baseNextBuilder().remove(), REMOVE, null); + } + + /** + * Tests that forwarding objective objects are built correctly using the + * remove(context) method. + */ + @Test + public void testNextRemoveWithContext() { + ObjectiveContext context = new MockObjectiveContext(); + checkNextBase(baseNextBuilder().remove(context), REMOVE, context); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/group/DefaultGroupDescriptionTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/group/DefaultGroupDescriptionTest.java new file mode 100644 index 00000000..66b0089e --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/group/DefaultGroupDescriptionTest.java @@ -0,0 +1,96 @@ +/* + * 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.group; + +import org.junit.Test; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficTreatment; + +import com.google.common.collect.ImmutableList; +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBaseClass; +import static org.onosproject.net.NetTestTools.APP_ID; +import static org.onosproject.net.NetTestTools.did; + +/** + * Default group description unit tests. + */ +public class DefaultGroupDescriptionTest { + byte[] keyData = "abcdefg".getBytes(); + private final GroupKey key = new DefaultGroupKey(keyData); + private final TrafficTreatment treatment = + DefaultTrafficTreatment.emptyTreatment(); + private final GroupBucket bucket = + DefaultGroupBucket.createSelectGroupBucket(treatment); + private final GroupBuckets groupBuckets = + new GroupBuckets(ImmutableList.of(bucket)); + private final DefaultGroupDescription d1 = + new DefaultGroupDescription(did("2"), + GroupDescription.Type.FAILOVER, + groupBuckets); + private final DefaultGroupDescription sameAsD1 = + new DefaultGroupDescription(d1); + private final DefaultGroupDescription d2 = + new DefaultGroupDescription(did("2"), + GroupDescription.Type.INDIRECT, + groupBuckets); + private final DefaultGroupDescription d3 = + new DefaultGroupDescription(did("3"), + GroupDescription.Type.FAILOVER, + groupBuckets, + key, + 711, + APP_ID); + + /** + * Checks that the Default group description class is immutable and can be + * inherited from. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutableBaseClass(DefaultGroupDescription.class); + } + + /** + * Tests for proper operation of equals(), hashCode() and toString() methods. + */ + @Test + public void checkEquals() { + new EqualsTester() + .addEqualityGroup(d1, sameAsD1) + .addEqualityGroup(d2) + .addEqualityGroup(d3) + .testEquals(); + } + + /** + * Checks that construction of an object was correct. + */ + @Test + public void testConstruction() { + assertThat(d3.deviceId(), is(did("3"))); + assertThat(d3.type(), is(GroupDescription.Type.FAILOVER)); + assertThat(d3.buckets(), is(groupBuckets)); + assertThat(d3.appId(), is(APP_ID)); + assertThat(d3.givenGroupId(), is(711)); + assertThat(key.key(), is(keyData)); + assertThat(d3.appCookie().key(), is(keyData)); + } +} + diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/group/DefaultGroupTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/group/DefaultGroupTest.java new file mode 100644 index 00000000..f27f266b --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/group/DefaultGroupTest.java @@ -0,0 +1,97 @@ +/* + * 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.group; + +import org.junit.Test; +import org.onosproject.core.DefaultGroupId; +import org.onosproject.core.GroupId; +import org.onosproject.net.NetTestTools; +import org.onosproject.net.flow.DefaultTrafficTreatment; + +import com.google.common.collect.ImmutableList; +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.*; +import static org.onosproject.net.NetTestTools.did; + +/** + * Unit tests for DefaultGroup class. + */ +public class DefaultGroupTest { + private final GroupId id1 = new DefaultGroupId(6); + private final GroupId id2 = new DefaultGroupId(7); + private final GroupBucket bucket = + DefaultGroupBucket.createSelectGroupBucket( + DefaultTrafficTreatment.emptyTreatment()); + private final GroupBuckets groupBuckets = + new GroupBuckets(ImmutableList.of(bucket)); + private final GroupDescription groupDesc1 = + new DefaultGroupDescription(did("1"), + GroupDescription.Type.FAILOVER, + groupBuckets); + private final GroupDescription groupDesc2 = + new DefaultGroupDescription(did("2"), + GroupDescription.Type.FAILOVER, + groupBuckets); + + DefaultGroup group1 = new DefaultGroup(id1, groupDesc1); + DefaultGroup sameAsGroup1 = new DefaultGroup(id1, groupDesc1); + DefaultGroup group2 = new DefaultGroup(id1, groupDesc2); + DefaultGroup group3 = new DefaultGroup(id2, groupDesc2); + + /** + * Tests for proper operation of equals(), hashCode() and toString() methods. + */ + @Test + public void checkEquals() { + new EqualsTester() + .addEqualityGroup(group1, sameAsGroup1) + .addEqualityGroup(group2) + .addEqualityGroup(group3) + .testEquals(); + } + + /** + * Tests that objects are created properly. + */ + @Test + public void checkConstruction() { + assertThat(group1.id(), is(id1)); + assertThat(group1.bytes(), is(0L)); + assertThat(group1.life(), is(0L)); + assertThat(group1.packets(), is(0L)); + assertThat(group1.referenceCount(), is(0L)); + assertThat(group1.buckets(), is(groupBuckets)); + assertThat(group1.state(), is(Group.GroupState.PENDING_ADD)); + } + + /** + * Tests that objects are created properly using the device based constructor. + */ + @Test + public void checkConstructionWithDid() { + DefaultGroup group = new DefaultGroup(id2, NetTestTools.did("1"), + GroupDescription.Type.INDIRECT, groupBuckets); + assertThat(group.id(), is(id2)); + assertThat(group.bytes(), is(0L)); + assertThat(group.life(), is(0L)); + assertThat(group.packets(), is(0L)); + assertThat(group.referenceCount(), is(0L)); + assertThat(group.deviceId(), is(NetTestTools.did("1"))); + assertThat(group.buckets(), is(groupBuckets)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/group/GroupBucketTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/group/GroupBucketTest.java new file mode 100644 index 00000000..0672ebf3 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/group/GroupBucketTest.java @@ -0,0 +1,133 @@ +/* + * 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.group; + +import org.junit.Test; +import org.onosproject.core.DefaultGroupId; +import org.onosproject.core.GroupId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficTreatment; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.onosproject.net.group.GroupDescription.Type.FAILOVER; +import static org.onosproject.net.group.GroupDescription.Type.INDIRECT; +import static org.onosproject.net.group.GroupDescription.Type.SELECT; + +/** + * Unit tests for the group bucket class. + */ +public class GroupBucketTest { + + private final GroupId groupId = new DefaultGroupId(7); + private final GroupId nullGroup = null; + + private final PortNumber nullPort = null; + + private final TrafficTreatment treatment = + DefaultTrafficTreatment.emptyTreatment(); + private final GroupBucket selectGroupBucket = + DefaultGroupBucket.createSelectGroupBucket(treatment); + private final GroupBucket sameAsSelectGroupBucket = + DefaultGroupBucket.createSelectGroupBucket(treatment); + private final GroupBucket failoverGroupBucket = + DefaultGroupBucket.createFailoverGroupBucket(treatment, + PortNumber.IN_PORT, groupId); + private final GroupBucket indirectGroupBucket = + DefaultGroupBucket.createIndirectGroupBucket(treatment); + private final GroupBucket selectGroupBucketWithWeight = + DefaultGroupBucket.createSelectGroupBucket(treatment, (short) 5); + + + /** + * Tests for proper operation of equals(), hashCode() and toString() methods. + */ + @Test + public void checkEquals() { + new EqualsTester() + .addEqualityGroup(selectGroupBucket, + sameAsSelectGroupBucket, + selectGroupBucketWithWeight) + .addEqualityGroup(failoverGroupBucket) + .addEqualityGroup(indirectGroupBucket) + .testEquals(); + } + + private void checkValues(GroupBucket bucket, GroupDescription.Type type, + long bytes, long packets, short weight, + GroupId groupId, PortNumber portNumber) { + assertThat(bucket.type(), is(type)); + assertThat(bucket.bytes(), is(bytes)); + assertThat(bucket.packets(), is(packets)); + assertThat(bucket.treatment(), is(treatment)); + assertThat(bucket.weight(), is(weight)); + assertThat(bucket.watchGroup(), is(groupId)); + assertThat(bucket.watchPort(), is(portNumber)); + } + + /** + * Checks that construction of a select group was correct. + */ + @Test + public void checkSelectGroup() { + // Casting needed because only the store accesses the set methods. + ((DefaultGroupBucket) selectGroupBucket).setBytes(4); + ((DefaultGroupBucket) selectGroupBucket).setPackets(44); + + checkValues(selectGroupBucket, SELECT, 4L, 44L, (short) 1, + nullGroup, nullPort); + } + + /** + * Checks that construction of a select group with a weight was correct. + */ + @Test + public void checkSelectGroupWithPriority() { + checkValues(selectGroupBucketWithWeight, SELECT, 0L, 0L, (short) 5, + nullGroup, nullPort); + } + + /** + * Checks that construction of an indirect group was correct. + */ + @Test + public void checkFailoverGroup() { + checkValues(failoverGroupBucket, FAILOVER, 0L, 0L, (short) -1, + groupId, PortNumber.IN_PORT); + } + /** + * Checks that construction of an indirect group was correct. + */ + @Test + public void checkIndirectGroup() { + checkValues(indirectGroupBucket, INDIRECT, 0L, 0L, (short) -1, + nullGroup, nullPort); + } + + /** + * Checks that a weight of 0 results in no group getting created. + */ + @Test + public void checkZeroWeight() { + GroupBucket bucket = + DefaultGroupBucket.createSelectGroupBucket(treatment, (short) 0); + assertThat(bucket, nullValue()); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/group/GroupOperationTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/group/GroupOperationTest.java new file mode 100644 index 00000000..5ee3a7ec --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/group/GroupOperationTest.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.group; + +import org.junit.Test; +import org.onosproject.core.DefaultGroupId; +import org.onosproject.core.GroupId; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficTreatment; + +import com.google.common.collect.ImmutableList; +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.net.group.GroupDescription.Type.ALL; +import static org.onosproject.net.group.GroupDescription.Type.INDIRECT; +import static org.onosproject.net.group.GroupOperation.Type.ADD; + +/** + * Tests for the group operation class. + */ +public class GroupOperationTest { + + private final GroupId groupId = new DefaultGroupId(6); + private final TrafficTreatment treatment = + DefaultTrafficTreatment.emptyTreatment(); + private final GroupBucket bucket = + DefaultGroupBucket.createSelectGroupBucket(treatment); + private final GroupBuckets groupBuckets = + new GroupBuckets(ImmutableList.of(bucket)); + private final GroupOperation op1 = + GroupOperation.createAddGroupOperation(groupId, ALL, groupBuckets); + private final GroupOperation sameAsOp1 = + GroupOperation.createAddGroupOperation(groupId, ALL, groupBuckets); + private final GroupOperation op2 = + GroupOperation.createAddGroupOperation(groupId, INDIRECT, groupBuckets); + private final GroupOperation op3 = + GroupOperation.createDeleteGroupOperation(groupId, INDIRECT); + private final GroupOperation op4 = + GroupOperation.createModifyGroupOperation(groupId, INDIRECT, groupBuckets); + + /** + * Checks that the GroupOperation class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(GroupOperation.class); + } + + /** + * Tests for proper operation of equals(), hashCode() and toString() methods. + */ + @Test + public void checkEquals() { + new EqualsTester() + .addEqualityGroup(op1, sameAsOp1) + .addEqualityGroup(op2) + .addEqualityGroup(op3) + .addEqualityGroup(op4) + .testEquals(); + } + + /** + * Checks that the construction of the add operation is correct. + */ + @Test + public void testAddGroupOperation() { + assertThat(op1.buckets(), is(groupBuckets)); + assertThat(op1.groupId(), is(groupId)); + assertThat(op1.groupType(), is(ALL)); + assertThat(op1.opType(), is(ADD)); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/host/DefaultHostDecriptionTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/host/DefaultHostDecriptionTest.java new file mode 100644 index 00000000..496269b6 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/host/DefaultHostDecriptionTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014 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.host; + +import org.junit.Test; +import org.onosproject.net.DeviceId; +import org.onosproject.net.HostLocation; +import org.onosproject.net.PortNumber; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; + +import com.google.common.collect.ImmutableSet; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Test for the default host description. + */ +public class DefaultHostDecriptionTest { + + private static final MacAddress MAC = MacAddress.valueOf("00:00:11:00:00:01"); + private static final VlanId VLAN = VlanId.vlanId((short) 10); + private static final IpAddress IP = IpAddress.valueOf("10.0.0.1"); + + private static final HostLocation LOC = new HostLocation( + DeviceId.deviceId("of:foo"), + PortNumber.portNumber(100), + 123L + ); + + @Test + public void basics() { + HostDescription host = + new DefaultHostDescription(MAC, VLAN, LOC, IP); + assertEquals("incorrect mac", MAC, host.hwAddress()); + assertEquals("incorrect vlan", VLAN, host.vlan()); + assertEquals("incorrect location", LOC, host.location()); + assertEquals("incorrect ip's", ImmutableSet.of(IP), host.ipAddress()); + assertTrue("incorrect toString", host.toString().contains("vlan=10")); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/host/HostEventTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/host/HostEventTest.java new file mode 100644 index 00000000..4a55d638 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/host/HostEventTest.java @@ -0,0 +1,72 @@ +/* + * Copyright 2014 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.host; + +import java.util.Set; + +import org.junit.Test; +import org.onosproject.event.AbstractEventTest; +import org.onosproject.net.DefaultHost; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Host; +import org.onosproject.net.HostId; +import org.onosproject.net.HostLocation; +import org.onosproject.net.PortNumber; +import org.onosproject.net.provider.ProviderId; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; + +import com.google.common.collect.Sets; + +public class HostEventTest extends AbstractEventTest { + + private Host createHost() { + MacAddress mac = MacAddress.valueOf("00:00:11:00:00:01"); + VlanId vlan = VlanId.vlanId((short) 10); + HostLocation loc = new HostLocation( + DeviceId.deviceId("of:foo"), + PortNumber.portNumber(100), + 123L + ); + Set ipset = Sets.newHashSet( + IpAddress.valueOf("10.0.0.1"), + IpAddress.valueOf("10.0.0.2") + ); + HostId hid = HostId.hostId(mac, vlan); + + return new DefaultHost( + new ProviderId("of", "foo"), hid, mac, vlan, loc, ipset); + } + + @Override + @Test + public void withTime() { + Host host = createHost(); + HostEvent event = new HostEvent(HostEvent.Type.HOST_ADDED, host, 123L); + validateEvent(event, HostEvent.Type.HOST_ADDED, host, 123L); + } + + @Override + @Test + public void withoutTime() { + Host host = createHost(); + long before = System.currentTimeMillis(); + HostEvent event = new HostEvent(HostEvent.Type.HOST_ADDED, host, before); + long after = System.currentTimeMillis(); + validateEvent(event, HostEvent.Type.HOST_ADDED, host, before, after); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/host/HostServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/host/HostServiceAdapter.java new file mode 100644 index 00000000..226dad06 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/host/HostServiceAdapter.java @@ -0,0 +1,102 @@ +/* + * Copyright 2014 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.host; + +import java.util.Set; + +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Host; +import org.onosproject.net.HostId; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; + +/** + * Test adapter for host service. + */ +public class HostServiceAdapter implements HostService { + @Override + public int getHostCount() { + return 0; + } + + @Override + public Iterable getHosts() { + return null; + } + + @Override + public Host getHost(HostId hostId) { + return null; + } + + @Override + public Set getHostsByVlan(VlanId vlanId) { + return null; + } + + @Override + public Set getHostsByMac(MacAddress mac) { + return null; + } + + @Override + public Set getHostsByIp(IpAddress ip) { + return null; + } + + @Override + public Set getConnectedHosts(ConnectPoint connectPoint) { + return null; + } + + @Override + public Set getConnectedHosts(DeviceId deviceId) { + return null; + } + + @Override + public void startMonitoringIp(IpAddress ip) { + } + + @Override + public void stopMonitoringIp(IpAddress ip) { + } + + @Override + public void requestMac(IpAddress ip) { + } + + @Override + public void addListener(HostListener listener) { + } + + @Override + public void removeListener(HostListener listener) { + } + + @Override + public Set getAddressBindings() { + return null; + } + + @Override + public Set getAddressBindingsForPort(ConnectPoint connectPoint) { + return null; + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/host/InterfaceIpAddressTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/host/InterfaceIpAddressTest.java new file mode 100644 index 00000000..6120b7ce --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/host/InterfaceIpAddressTest.java @@ -0,0 +1,246 @@ +/* + * Copyright 2014 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.host; + +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onlab.packet.IpPrefix; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + +/** + * Tests for class {@link InterfaceIpAddress}. + */ +public class InterfaceIpAddressTest { + private static final IpAddress IP_ADDRESS = IpAddress.valueOf("1.2.3.4"); + private static final IpPrefix SUBNET_ADDRESS = + IpPrefix.valueOf("1.2.0.0/16"); + private static final IpAddress BROADCAST_ADDRESS = + IpAddress.valueOf("1.2.0.255"); // NOTE: non-default broadcast + private static final IpAddress PEER_ADDRESS = IpAddress.valueOf("5.6.7.8"); + + private static final IpAddress IP_ADDRESS2 = IpAddress.valueOf("10.2.3.4"); + private static final IpPrefix SUBNET_ADDRESS2 = + IpPrefix.valueOf("10.2.0.0/16"); + private static final IpAddress BROADCAST_ADDRESS2 = + IpAddress.valueOf("10.2.0.255"); // NOTE: non-default broadcast + private static final IpAddress PEER_ADDRESS2 = + IpAddress.valueOf("50.6.7.8"); + + /** + * Tests valid class copy constructor. + */ + @Test + public void testCopyConstructor() { + InterfaceIpAddress fromAddr; + InterfaceIpAddress toAddr; + + // Regular interface address with default broadcast address + fromAddr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS); + toAddr = new InterfaceIpAddress(fromAddr); + assertThat(toAddr.ipAddress(), is(fromAddr.ipAddress())); + assertThat(toAddr.subnetAddress(), is(fromAddr.subnetAddress())); + assertThat(toAddr.broadcastAddress(), is(fromAddr.broadcastAddress())); + assertThat(toAddr.peerAddress(), is(fromAddr.peerAddress())); + + // Interface address with non-default broadcast address + fromAddr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, + BROADCAST_ADDRESS); + toAddr = new InterfaceIpAddress(fromAddr); + assertThat(toAddr.ipAddress(), is(fromAddr.ipAddress())); + assertThat(toAddr.subnetAddress(), is(fromAddr.subnetAddress())); + assertThat(toAddr.broadcastAddress(), is(fromAddr.broadcastAddress())); + assertThat(toAddr.peerAddress(), is(fromAddr.peerAddress())); + + // Point-to-point address with peer IP address + fromAddr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, null, + PEER_ADDRESS); + toAddr = new InterfaceIpAddress(fromAddr); + assertThat(toAddr.ipAddress(), is(fromAddr.ipAddress())); + assertThat(toAddr.subnetAddress(), is(fromAddr.subnetAddress())); + assertThat(toAddr.broadcastAddress(), is(fromAddr.broadcastAddress())); + assertThat(toAddr.peerAddress(), is(fromAddr.peerAddress())); + } + + /** + * Tests invalid class copy constructor for a null object to copy from. + */ + @Test(expected = NullPointerException.class) + public void testInvalidConstructorNullObject() { + InterfaceIpAddress fromAddr = null; + InterfaceIpAddress toAddr = new InterfaceIpAddress(fromAddr); + } + + /** + * Tests valid class constructor for regular interface address with + * default broadcast address. + */ + @Test + public void testConstructorForDefaultBroadcastAddress() { + InterfaceIpAddress addr = + new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS); + assertThat(addr.ipAddress(), is(IP_ADDRESS)); + assertThat(addr.subnetAddress(), is(SUBNET_ADDRESS)); + assertThat(addr.broadcastAddress(), nullValue()); + assertThat(addr.peerAddress(), nullValue()); + } + + /** + * Tests valid class constructor for interface address with + * non-default broadcast address. + */ + @Test + public void testConstructorForNonDefaultBroadcastAddress() { + InterfaceIpAddress addr = + new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, + BROADCAST_ADDRESS); + + assertThat(addr.ipAddress(), is(IP_ADDRESS)); + assertThat(addr.subnetAddress(), is(SUBNET_ADDRESS)); + assertThat(addr.broadcastAddress(), is(BROADCAST_ADDRESS)); + assertThat(addr.peerAddress(), nullValue()); + } + + /** + * Tests valid class constructor for point-to-point interface address with + * peer address. + */ + @Test + public void testConstructorForPointToPointAddress() { + InterfaceIpAddress addr = + new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, null, + PEER_ADDRESS); + + assertThat(addr.ipAddress(), is(IP_ADDRESS)); + assertThat(addr.subnetAddress(), is(SUBNET_ADDRESS)); + assertThat(addr.broadcastAddress(), nullValue()); + assertThat(addr.peerAddress(), is(PEER_ADDRESS)); + } + + /** + * Tests getting the fields of an interface address. + */ + @Test + public void testGetFields() { + InterfaceIpAddress addr; + + // Regular interface address with default broadcast address + addr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS); + assertThat(addr.ipAddress().toString(), is("1.2.3.4")); + assertThat(addr.subnetAddress().toString(), is("1.2.0.0/16")); + assertThat(addr.broadcastAddress(), is(nullValue())); // TODO: Fix + assertThat(addr.peerAddress(), is(nullValue())); + + // Interface address with non-default broadcast address + addr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, + BROADCAST_ADDRESS); + assertThat(addr.ipAddress().toString(), is("1.2.3.4")); + assertThat(addr.subnetAddress().toString(), is("1.2.0.0/16")); + assertThat(addr.broadcastAddress().toString(), is("1.2.0.255")); + assertThat(addr.peerAddress(), is(nullValue())); + + // Point-to-point address with peer IP address + addr = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, null, + PEER_ADDRESS); + assertThat(addr.ipAddress().toString(), is("1.2.3.4")); + assertThat(addr.subnetAddress().toString(), is("1.2.0.0/16")); + assertThat(addr.broadcastAddress(), is(nullValue())); + assertThat(addr.peerAddress().toString(), is("5.6.7.8")); + } + + /** + * Tests equality of {@link InterfaceIpAddress}. + */ + @Test + public void testEquality() { + InterfaceIpAddress addr1, addr2; + + // Regular interface address with default broadcast address + addr1 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS); + addr2 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS); + assertThat(addr1, is(addr2)); + + // Interface address with non-default broadcast address + addr1 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, + BROADCAST_ADDRESS); + addr2 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, + BROADCAST_ADDRESS); + assertThat(addr1, is(addr2)); + + // Point-to-point address with peer IP address + addr1 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, null, + PEER_ADDRESS); + addr2 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, null, + PEER_ADDRESS); + assertThat(addr1, is(addr2)); + } + + /** + * Tests non-equality of {@link InterfaceIpAddress}. + */ + @Test + public void testNonEquality() { + InterfaceIpAddress addr1, addr2, addr3, addr4; + + // Regular interface address with default broadcast address + addr1 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS); + // Interface address with non-default broadcast address + addr2 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, + BROADCAST_ADDRESS); + // Point-to-point address with peer IP address + addr3 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, null, + PEER_ADDRESS); + + // Test interface addresses with different properties: + // - default-broadcast vs non-default broadcast + // - regular vs point-to-point + assertThat(addr1, is(not(addr2))); + assertThat(addr1, is(not(addr3))); + assertThat(addr2, is(not(addr3))); + + // Test regular interface address with default broadcast address + addr4 = new InterfaceIpAddress(IP_ADDRESS2, SUBNET_ADDRESS); + assertThat(addr1, is(not(addr4))); + addr4 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS2); + assertThat(addr1, is(not(addr4))); + + // Test interface address with non-default broadcast address + addr4 = new InterfaceIpAddress(IP_ADDRESS2, SUBNET_ADDRESS, + BROADCAST_ADDRESS); + assertThat(addr2, is(not(addr4))); + addr4 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS2, + BROADCAST_ADDRESS); + assertThat(addr2, is(not(addr4))); + addr4 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, + BROADCAST_ADDRESS2); + assertThat(addr2, is(not(addr4))); + + // Test point-to-point address with peer IP address + addr4 = new InterfaceIpAddress(IP_ADDRESS2, SUBNET_ADDRESS, null, + PEER_ADDRESS); + assertThat(addr3, is(not(addr4))); + addr4 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS2, null, + PEER_ADDRESS); + assertThat(addr3, is(not(addr4))); + addr4 = new InterfaceIpAddress(IP_ADDRESS, SUBNET_ADDRESS, null, + PEER_ADDRESS2); + assertThat(addr3, is(not(addr4))); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/host/PortAddressesTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/host/PortAddressesTest.java new file mode 100644 index 00000000..7c10cd15 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/host/PortAddressesTest.java @@ -0,0 +1,113 @@ +/* + * 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.host; + +import java.util.Set; + +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.IpAddress; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.NetTestTools; + +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +import com.google.common.collect.ImmutableSet; +import com.google.common.testing.EqualsTester; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Unit tests for port addresses class. + */ +public class PortAddressesTest { + + PortAddresses addresses1; + PortAddresses sameAsAddresses1; + PortAddresses addresses2; + PortAddresses addresses3; + + private static final ConnectPoint CONNECT_POINT1 = + NetTestTools.connectPoint("cp1", 1); + private static final IpAddress IP_ADDRESS1 = IpAddress.valueOf("1.2.3.4"); + private static final IpPrefix SUBNET_ADDRESS1 = + IpPrefix.valueOf("1.2.0.0/16"); + private static final InterfaceIpAddress INTERFACE_ADDRESS_1 = + new InterfaceIpAddress(IP_ADDRESS1, SUBNET_ADDRESS1); + + private static final ConnectPoint CONNECT_POINT2 = + NetTestTools.connectPoint("cp2", 1); + private static final IpAddress IP_ADDRESS2 = IpAddress.valueOf("1.2.3.5"); + private static final IpPrefix SUBNET_ADDRESS2 = + IpPrefix.valueOf("1.3.0.0/16"); + private static final InterfaceIpAddress INTERFACE_ADDRESS_2 = + new InterfaceIpAddress(IP_ADDRESS2, SUBNET_ADDRESS2); + + Set ipAddresses; + + + /** + * Initializes local data used by all test cases. + */ + @Before + public void setUpAddresses() { + ipAddresses = ImmutableSet.of(INTERFACE_ADDRESS_1, + INTERFACE_ADDRESS_2); + addresses1 = new PortAddresses(CONNECT_POINT1, ipAddresses, + MacAddress.BROADCAST, VlanId.NONE); + sameAsAddresses1 = new PortAddresses(CONNECT_POINT1, ipAddresses, + MacAddress.BROADCAST, VlanId.NONE); + addresses2 = new PortAddresses(CONNECT_POINT2, ipAddresses, + MacAddress.BROADCAST, VlanId.NONE); + addresses3 = new PortAddresses(CONNECT_POINT2, ipAddresses, + MacAddress.ZERO, VlanId.NONE); + } + + /** + * Checks that the PortAddresses class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(PortAddresses.class); + } + + /** + * Checks the operation of the equals(), hash() and toString() + * methods. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(addresses1, sameAsAddresses1) + .addEqualityGroup(addresses2) + .addEqualityGroup(addresses3) + .testEquals(); + } + + /** + * Tests that object are created correctly. + */ + @Test + public void testConstruction() { + assertThat(addresses1.mac(), is(MacAddress.BROADCAST)); + assertThat(addresses1.connectPoint(), is(CONNECT_POINT1)); + assertThat(addresses1.ipAddresses(), is(ipAddresses)); + assertThat(addresses1.vlan(), is(VlanId.NONE)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/AbstractIntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/AbstractIntentTest.java new file mode 100644 index 00000000..6bb7e28f --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/AbstractIntentTest.java @@ -0,0 +1,35 @@ +/* + * Copyright 2014-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.intent; + +import org.junit.After; +import org.junit.Before; +import org.onosproject.core.IdGenerator; + +public abstract class AbstractIntentTest { + + protected IdGenerator idGenerator = new MockIdGenerator(); + + @Before + public void setUp() throws Exception { + Intent.bindIdGenerator(idGenerator); + } + + @After + public void tearDown() { + Intent.unbindIdGenerator(idGenerator); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/ConnectivityIntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/ConnectivityIntentTest.java new file mode 100644 index 00000000..e03ed850 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/ConnectivityIntentTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2014-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.intent; + +import java.util.Set; + +import org.onosproject.core.ApplicationId; +import org.onosproject.TestApplicationId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +/** + * Base facilities to test various connectivity tests. + */ +public abstract class ConnectivityIntentTest extends IntentTest { + + public static final ApplicationId APPID = new TestApplicationId("foo"); + + public static final IntentId IID = new IntentId(123); + public static final TrafficSelector MATCH = DefaultTrafficSelector.emptySelector(); + public static final TrafficTreatment NOP = DefaultTrafficTreatment.emptyTreatment(); + + public static final ConnectPoint P1 = new ConnectPoint(DeviceId.deviceId("111"), PortNumber.portNumber(0x1)); + public static final ConnectPoint P2 = new ConnectPoint(DeviceId.deviceId("222"), PortNumber.portNumber(0x2)); + public static final ConnectPoint P3 = new ConnectPoint(DeviceId.deviceId("333"), PortNumber.portNumber(0x3)); + + public static final Set PS1 = itemSet(new ConnectPoint[]{P1, P3}); + public static final Set PS2 = itemSet(new ConnectPoint[]{P2, P3}); +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java new file mode 100644 index 00000000..9b9f7cec --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/FakeIntentManager.java @@ -0,0 +1,268 @@ +/* + * Copyright 2014-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.intent; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Fake implementation of the intent service to assist in developing tests of + * the interface contract. + */ +public class FakeIntentManager implements TestableIntentService { + + private final Map intents = new HashMap<>(); + private final Map intentStates = new HashMap<>(); + private final Map> installables = new HashMap<>(); + private final Set listeners = new HashSet<>(); + + private final Map, IntentCompiler> compilers = new HashMap<>(); + + private final ExecutorService executor = Executors.newSingleThreadExecutor(); + private final List exceptions = new ArrayList<>(); + + @Override + public List getExceptions() { + return exceptions; + } + + // Provides an out-of-thread simulation of intent submit life-cycle + private void executeSubmit(final Intent intent) { + registerSubclassCompilerIfNeeded(intent); + executor.execute(new Runnable() { + @Override + public void run() { + try { + executeCompilingPhase(intent); + } catch (IntentException e) { + exceptions.add(e); + } + } + }); + } + + // Provides an out-of-thread simulation of intent withdraw life-cycle + private void executeWithdraw(final Intent intent) { + executor.execute(new Runnable() { + @Override + public void run() { + try { + List installable = getInstallable(intent.key()); + executeWithdrawingPhase(intent, installable); + } catch (IntentException e) { + exceptions.add(e); + } + + } + }); + } + + private IntentCompiler getCompiler(T intent) { + @SuppressWarnings("unchecked") + IntentCompiler compiler = (IntentCompiler) compilers.get(intent.getClass()); + if (compiler == null) { + throw new IntentException("no compiler for class " + intent.getClass()); + } + return compiler; + } + + private void executeCompilingPhase(T intent) { + setState(intent, IntentState.COMPILING); + try { + // For the fake, we compile using a single level pass + List installable = new ArrayList<>(); + for (Intent compiled : getCompiler(intent).compile(intent, null, null)) { + installable.add(compiled); + } + executeInstallingPhase(intent, installable); + + } catch (IntentException e) { + setState(intent, IntentState.FAILED); + dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent)); + } + } + + private void executeInstallingPhase(Intent intent, + List installable) { + setState(intent, IntentState.INSTALLING); + try { + setState(intent, IntentState.INSTALLED); + putInstallable(intent.key(), installable); + dispatch(new IntentEvent(IntentEvent.Type.INSTALLED, intent)); + + } catch (IntentException e) { + setState(intent, IntentState.FAILED); + dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent)); + } + } + + private void executeWithdrawingPhase(Intent intent, + List installable) { + setState(intent, IntentState.WITHDRAWING); + try { + removeInstallable(intent.key()); + setState(intent, IntentState.WITHDRAWN); + dispatch(new IntentEvent(IntentEvent.Type.WITHDRAWN, intent)); + } catch (IntentException e) { + // FIXME: Rework this to always go from WITHDRAWING to WITHDRAWN! + setState(intent, IntentState.FAILED); + dispatch(new IntentEvent(IntentEvent.Type.FAILED, intent)); + } + } + + // Sets the internal state for the given intent and dispatches an event + private void setState(Intent intent, IntentState state) { + intentStates.put(intent.key(), state); + } + + private void putInstallable(Key key, List installable) { + installables.put(key, installable); + } + + private void removeInstallable(Key key) { + installables.remove(key); + } + + private List getInstallable(Key key) { + List installable = installables.get(key); + if (installable != null) { + return installable; + } else { + return Collections.emptyList(); + } + } + + @Override + public void submit(Intent intent) { + intents.put(intent.key(), intent); + setState(intent, IntentState.INSTALL_REQ); + dispatch(new IntentEvent(IntentEvent.Type.INSTALL_REQ, intent)); + executeSubmit(intent); + } + + @Override + public void withdraw(Intent intent) { + intents.remove(intent.key()); + executeWithdraw(intent); + } + + @Override + public void purge(Intent intent) { + IntentState currentState = intentStates.get(intent.key()); + if (currentState == IntentState.WITHDRAWN + || currentState == IntentState.FAILED) { + intents.remove(intent.key()); + installables.remove(intent.key()); + intentStates.remove(intent.key()); + } + } + + @Override + public Set getIntents() { + return Collections.unmodifiableSet(new HashSet<>(intents.values())); + } + + @Override + public Iterable getIntentData() { + throw new UnsupportedOperationException(); + } + + @Override + public long getIntentCount() { + return intents.size(); + } + + @Override + public Intent getIntent(Key intentKey) { + return intents.get(intentKey); + } + + @Override + public IntentState getIntentState(Key intentKey) { + return intentStates.get(intentKey); + } + + @Override + public List getInstallableIntents(Key intentKey) { + return installables.get(intentKey); + } + + @Override + public boolean isLocal(Key intentKey) { + return true; + } + + @Override + public Iterable getPending() { + return Collections.emptyList(); + } + + @Override + public void addListener(IntentListener listener) { + listeners.add(listener); + } + + @Override + public void removeListener(IntentListener listener) { + listeners.remove(listener); + } + + private void dispatch(IntentEvent event) { + for (IntentListener listener : listeners) { + listener.event(event); + } + } + + @Override + public void registerCompiler(Class cls, + IntentCompiler compiler) { + compilers.put(cls, compiler); + } + + @Override + public void unregisterCompiler(Class cls) { + compilers.remove(cls); + } + + @Override + public Map, IntentCompiler> getCompilers() { + return Collections.unmodifiableMap(compilers); + } + + private void registerSubclassCompilerIfNeeded(Intent intent) { + if (!compilers.containsKey(intent.getClass())) { + Class cls = intent.getClass(); + while (cls != Object.class) { + // As long as we're within the Intent class descendants + if (Intent.class.isAssignableFrom(cls)) { + IntentCompiler compiler = compilers.get(cls); + if (compiler != null) { + compilers.put(intent.getClass(), compiler); + return; + } + } + cls = cls.getSuperclass(); + } + } + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/HostToHostIntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/HostToHostIntentTest.java new file mode 100644 index 00000000..3f7650e4 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/HostToHostIntentTest.java @@ -0,0 +1,126 @@ +/* + * Copyright 2014-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.intent; + +import org.junit.Test; +import org.onosproject.TestApplicationId; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.HostId; +import org.onosproject.net.flow.TrafficSelector; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.net.NetTestTools.hid; + +/** + * Unit tests for the HostToHostIntent class. + */ +public class HostToHostIntentTest extends IntentTest { + private final TrafficSelector selector = new IntentTestsMocks.MockSelector(); + private final IntentTestsMocks.MockTreatment treatment = new IntentTestsMocks.MockTreatment(); + private final HostId id1 = hid("12:34:56:78:91:ab/1"); + private final HostId id2 = hid("12:34:56:78:92:ab/1"); + private final HostId id3 = hid("12:34:56:78:93:ab/1"); + + private static final ApplicationId APPID = new TestApplicationId("foo"); + + private HostToHostIntent makeHostToHost(HostId one, HostId two) { + return HostToHostIntent.builder() + .appId(APPID) + .one(one) + .two(two) + .selector(selector) + .treatment(treatment) + .build(); + } + + /** + * Tests the equals() method where two HostToHostIntents have references + * to the same hosts. These should compare equal. + */ + @Test + public void testSameEquals() { + + HostId one = hid("00:00:00:00:00:01/-1"); + HostId two = hid("00:00:00:00:00:02/-1"); + HostToHostIntent i1 = makeHostToHost(one, two); + HostToHostIntent i2 = makeHostToHost(one, two); + + assertThat(i1.one(), is(equalTo(i2.one()))); + assertThat(i1.two(), is(equalTo(i2.two()))); + } + + /** + * Checks that the HostToHostIntent class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(HostToHostIntent.class); + } + + /** + * Tests equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + final HostToHostIntent intent1 = HostToHostIntent.builder() + .appId(APPID) + .one(id1) + .two(id2) + .selector(selector) + .treatment(treatment) + .build(); + + final HostToHostIntent intent2 = HostToHostIntent.builder() + .appId(APPID) + .one(id2) + .two(id3) + .selector(selector) + .treatment(treatment) + .build(); + + new EqualsTester() + .addEqualityGroup(intent1) + .addEqualityGroup(intent2) + .testEquals(); + } + + @Override + protected Intent createOne() { + return HostToHostIntent.builder() + .appId(APPID) + .one(id1) + .two(id2) + .selector(selector) + .treatment(treatment) + .build(); + } + + @Override + protected Intent createAnother() { + return HostToHostIntent.builder() + .appId(APPID) + .one(id1) + .two(id3) + .selector(selector) + .treatment(treatment) + .build(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentDataTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentDataTest.java new file mode 100644 index 00000000..9c4cf7e0 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentDataTest.java @@ -0,0 +1,179 @@ +/* + * 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.intent; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.core.IdGenerator; +import org.onosproject.store.Timestamp; + +import com.google.common.testing.EqualsTester; + +import static junit.framework.TestCase.assertFalse; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertTrue; +import static org.onosproject.net.intent.IntentTestsMocks.MockIntent; +import static org.onosproject.net.intent.IntentTestsMocks.MockTimestamp; + +/** + * Unit tests for intent data objects. + */ +public class IntentDataTest { + + private Timestamp timestamp1; + private Timestamp timestamp2; + private Timestamp timestamp3; + + private Intent intent1; + private Intent intent2; + private Intent intent3; + + private IntentData data1; + private IntentData data1Copy; + private IntentData data2; + private IntentData data2Copy; + private IntentData data3; + private IntentData data3Copy; + + IdGenerator idGenerator; + + @Before + public void setUpTest() { + idGenerator = new MockIdGenerator(); + Intent.bindIdGenerator(idGenerator); + + timestamp1 = new MockTimestamp(1); + timestamp2 = new MockTimestamp(2); + timestamp3 = new MockTimestamp(3); + + intent1 = new MockIntent(1L); + intent2 = new MockIntent(2L); + intent3 = new MockIntent(3L); + + data1 = new IntentData(intent1, IntentState.INSTALLED, timestamp1); + data1Copy = new IntentData(intent1, IntentState.INSTALLED, timestamp1); + data2 = new IntentData(intent2, IntentState.INSTALLED, timestamp2); + data2Copy = new IntentData(intent2, IntentState.INSTALLED, timestamp2); + data3 = new IntentData(intent3, IntentState.INSTALLED, timestamp3); + data3Copy = new IntentData(intent3, IntentState.INSTALLED, timestamp3); + } + + @After + public void tearDownTest() { + Intent.unbindIdGenerator(idGenerator); + } + + /** + * Checks that intent data objects are properly constructed. + */ + @Test + public void checkConstruction() { + assertThat(data1.state(), is(IntentState.INSTALLED)); + assertThat(data1.version(), is(timestamp1)); + assertThat(data1.intent(), is(intent1)); + } + + /** + * Checks equals() for intent data objects. + */ + @Test + public void checkEquals() { + new EqualsTester() + .addEqualityGroup(data1, data1Copy) + .addEqualityGroup(data2, data2Copy) + .addEqualityGroup(data3, data3Copy) + .testEquals(); + } + + @Test + public void testIsUpdateAcceptable() { + // Going from null to something is always allowed + assertTrue(IntentData.isUpdateAcceptable(null, data1)); + + // we can go from older version to newer but not they other way + assertTrue(IntentData.isUpdateAcceptable(data1, data2)); + assertFalse(IntentData.isUpdateAcceptable(data2, data1)); + + IntentData installing = new IntentData(intent1, IntentState.INSTALLING, timestamp1); + IntentData installed = new IntentData(intent1, IntentState.INSTALLED, timestamp1); + IntentData withdrawing = new IntentData(intent1, IntentState.WITHDRAWING, timestamp1); + IntentData withdrawn = new IntentData(intent1, IntentState.WITHDRAWN, timestamp1); + + IntentData failed = new IntentData(intent1, IntentState.FAILED, timestamp1); + IntentData purgeReq = new IntentData(intent1, IntentState.PURGE_REQ, timestamp1); + + IntentData compiling = new IntentData(intent1, IntentState.COMPILING, timestamp1); + IntentData recompiling = new IntentData(intent1, IntentState.RECOMPILING, timestamp1); + IntentData installReq = new IntentData(intent1, IntentState.INSTALL_REQ, timestamp1); + IntentData withdrawReq = new IntentData(intent1, IntentState.WITHDRAW_REQ, timestamp1); + + // We can't change to the same state + assertFalse(IntentData.isUpdateAcceptable(installing, installing)); + assertFalse(IntentData.isUpdateAcceptable(installed, installed)); + + // From installing we can change to installed + assertTrue(IntentData.isUpdateAcceptable(installing, installed)); + + // Sanity checks in case the manager submits bogus state transitions + assertFalse(IntentData.isUpdateAcceptable(installing, withdrawing)); + assertFalse(IntentData.isUpdateAcceptable(installing, withdrawn)); + assertFalse(IntentData.isUpdateAcceptable(installed, withdrawing)); + assertFalse(IntentData.isUpdateAcceptable(installed, withdrawn)); + + // We can't change to the same state + assertFalse(IntentData.isUpdateAcceptable(withdrawing, withdrawing)); + assertFalse(IntentData.isUpdateAcceptable(withdrawn, withdrawn)); + + // From withdrawing we can change to withdrawn + assertTrue(IntentData.isUpdateAcceptable(withdrawing, withdrawn)); + + // Sanity checks in case the manager submits bogus state transitions + assertFalse(IntentData.isUpdateAcceptable(withdrawing, installing)); + assertFalse(IntentData.isUpdateAcceptable(withdrawing, installed)); + assertFalse(IntentData.isUpdateAcceptable(withdrawn, installing)); + assertFalse(IntentData.isUpdateAcceptable(withdrawn, installed)); + + // We can't go from failed to failed + assertFalse(IntentData.isUpdateAcceptable(failed, failed)); + + // But we can go from any install* or withdraw* state to failed + assertTrue(IntentData.isUpdateAcceptable(installing, failed)); + assertTrue(IntentData.isUpdateAcceptable(installed, failed)); + assertTrue(IntentData.isUpdateAcceptable(withdrawing, failed)); + assertTrue(IntentData.isUpdateAcceptable(withdrawn, failed)); + + // We can go from anything to purgeReq + assertTrue(IntentData.isUpdateAcceptable(installing, purgeReq)); + assertTrue(IntentData.isUpdateAcceptable(installed, purgeReq)); + assertTrue(IntentData.isUpdateAcceptable(withdrawing, purgeReq)); + assertTrue(IntentData.isUpdateAcceptable(withdrawn, purgeReq)); + assertTrue(IntentData.isUpdateAcceptable(failed, purgeReq)); + + // We can't go from purgeReq back to anything else + assertFalse(IntentData.isUpdateAcceptable(purgeReq, withdrawn)); + assertFalse(IntentData.isUpdateAcceptable(purgeReq, withdrawing)); + assertFalse(IntentData.isUpdateAcceptable(purgeReq, installed)); + assertFalse(IntentData.isUpdateAcceptable(purgeReq, installing)); + + // We're never allowed to store transient states + assertFalse(IntentData.isUpdateAcceptable(installing, compiling)); + assertFalse(IntentData.isUpdateAcceptable(installing, recompiling)); + assertFalse(IntentData.isUpdateAcceptable(installing, installReq)); + assertFalse(IntentData.isUpdateAcceptable(installing, withdrawReq)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentExceptionTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentExceptionTest.java new file mode 100644 index 00000000..f26ee639 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentExceptionTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014 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.intent; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Test of the intent exception. + */ +public class IntentExceptionTest { + + @Test + public void basics() { + validate(new IntentException(), null, null); + validate(new IntentException("foo"), "foo", null); + + Throwable cause = new NullPointerException("bar"); + validate(new IntentException("foo", cause), "foo", cause); + } + + /** + * Validates that the specified exception has the correct message and cause. + * + * @param e exception to test + * @param message expected message + * @param cause expected cause + */ + protected void validate(RuntimeException e, String message, Throwable cause) { + assertEquals("incorrect message", message, e.getMessage()); + assertEquals("incorrect cause", cause, e.getCause()); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentIdTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentIdTest.java new file mode 100644 index 00000000..e2987b54 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentIdTest.java @@ -0,0 +1,95 @@ +/* + * Copyright 2014 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.intent; + +import org.junit.Test; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +/** + * This class tests the immutability, equality, and non-equality of + * {@link IntentId}. + */ +public class IntentIdTest { + /** + * Tests the immutability of {@link IntentId}. + */ + @Test + public void intentIdFollowsGuidelineForImmutableObject() { + assertThatClassIsImmutable(IntentId.class); + } + + /** + * Tests equality of {@link IntentId}. + */ + @Test + public void testEquality() { + IntentId id1 = new IntentId(1L); + IntentId id2 = new IntentId(1L); + + assertThat(id1, is(id2)); + } + + /** + * Tests non-equality of {@link IntentId}. + */ + @Test + public void testNonEquality() { + IntentId id1 = new IntentId(1L); + IntentId id2 = new IntentId(2L); + + assertThat(id1, is(not(id2))); + } + + @Test + public void valueOf() { + IntentId id = new IntentId(0xdeadbeefL); + assertEquals("incorrect valueOf", id, IntentId.valueOf(0xdeadbeefL)); + } + + /** + * Tests the equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + final IntentId id1 = new IntentId(11111L); + final IntentId sameAsId1 = new IntentId(11111L); + final IntentId id2 = new IntentId(22222L); + + new EqualsTester() + .addEqualityGroup(id1, sameAsId1) + .addEqualityGroup(id2) + .testEquals(); + } + + /** + * Tests construction of an IntentId object. + */ + @Test + public void testConstruction() { + final IntentId id1 = new IntentId(987654321L); + assertEquals(id1.fingerprint(), 987654321L); + + final IntentId emptyId = new IntentId(); + assertEquals(emptyId.fingerprint(), 0L); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentServiceAdapter.java new file mode 100644 index 00000000..13786b4e --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentServiceAdapter.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.intent; + +import java.util.List; + +/** + * Test adapter for intent service. + */ +public class IntentServiceAdapter implements IntentService { + @Override + public void submit(Intent intent) { + + } + + @Override + public void withdraw(Intent intent) { + + } + + @Override + public void purge(Intent intent) { + + } + + @Override + public Iterable getIntents() { + return null; + } + + @Override + public Iterable getIntentData() { + return null; + } + + @Override + public long getIntentCount() { + return 0; + } + + @Override + public Intent getIntent(Key intentKey) { + return null; + } + + @Override + public IntentState getIntentState(Key intentKey) { + return IntentState.INSTALLED; + } + + @Override + public List getInstallableIntents(Key intentKey) { + return null; + } + + @Override + public boolean isLocal(Key intentKey) { + return false; + } + + @Override + public Iterable getPending() { + return null; + } + + @Override + public void addListener(IntentListener listener) { + + } + + @Override + public void removeListener(IntentListener listener) { + + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentServiceTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentServiceTest.java new file mode 100644 index 00000000..60857cac --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentServiceTest.java @@ -0,0 +1,252 @@ +/* + * Copyright 2014-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.intent; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.core.IdGenerator; +import org.onosproject.net.resource.link.LinkResourceAllocations; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import static org.junit.Assert.*; +import static org.onosproject.net.intent.IntentEvent.Type.*; + +/** + * Suite of tests for the intent service contract. + */ +public class IntentServiceTest { + + public static final int IID = 123; + public static final int INSTALLABLE_IID = 234; + + protected static final int GRACE_MS = 500; // millis + + protected TestableIntentService service; + protected TestListener listener = new TestListener(); + protected IdGenerator idGenerator = new MockIdGenerator(); + + @Before + public void setUp() { + service = createIntentService(); + service.addListener(listener); + Intent.bindIdGenerator(idGenerator); + } + + @After + public void tearDown() { + service.removeListener(listener); + Intent.unbindIdGenerator(idGenerator); + } + + /** + * Creates a service instance appropriately instrumented for testing. + * + * @return testable intent service + */ + protected TestableIntentService createIntentService() { + return new FakeIntentManager(); + } + + @Test + public void basics() { + // Make sure there are no intents + assertEquals("incorrect intent count", 0, service.getIntentCount()); + + // Register a compiler and an installer both setup for success. + service.registerCompiler(TestIntent.class, new TestCompiler(new TestInstallableIntent(INSTALLABLE_IID))); + + final Intent intent = new TestIntent(IID); + service.submit(intent); + + // Allow a small window of time until the intent is in the expected state + TestTools.assertAfter(GRACE_MS, new Runnable() { + @Override + public void run() { + assertEquals("incorrect intent state", IntentState.INSTALLED, + service.getIntentState(intent.key())); + } + }); + + // Make sure that all expected events have been emitted + validateEvents(intent, INSTALL_REQ, INSTALLED); + + // Make sure there is just one intent (and is ours) + assertEquals("incorrect intent count", 1, service.getIntentCount()); + + // Reset the listener events + listener.events.clear(); + + // Now withdraw the intent + service.withdraw(intent); + + // Allow a small window of time until the event is in the expected state + TestTools.assertAfter(GRACE_MS, new Runnable() { + @Override + public void run() { + assertEquals("incorrect intent state", IntentState.WITHDRAWN, + service.getIntentState(intent.key())); + } + }); + + // Make sure that all expected events have been emitted + validateEvents(intent, WITHDRAWN); + + // TODO: discuss what is the fate of intents after they have been withdrawn + // Make sure that the intent is no longer in the system +// assertEquals("incorrect intent count", 0, service.getIntents().size()); +// assertNull("intent should not be found", service.getIntent(intent.id())); +// assertNull("intent state should not be found", service.getIntentState(intent.id())); + } + + @Test + public void failedCompilation() { + // Register a compiler programmed for success + service.registerCompiler(TestIntent.class, new TestCompiler(true)); + + // Submit an intent + final Intent intent = new TestIntent(IID); + service.submit(intent); + + // Allow a small window of time until the intent is in the expected state + TestTools.assertAfter(GRACE_MS, new Runnable() { + @Override + public void run() { + assertEquals("incorrect intent state", IntentState.FAILED, + service.getIntentState(intent.key())); + } + }); + + // Make sure that all expected events have been emitted + validateEvents(intent, INSTALL_REQ, FAILED); + } + + /** + * Validates that the test event listener has received the following events + * for the specified intent. Events received for other intents will not be + * considered. + * + * @param intent intent subject + * @param types list of event types for which events are expected + */ + protected void validateEvents(Intent intent, IntentEvent.Type... types) { + Iterator events = listener.events.iterator(); + for (IntentEvent.Type type : types) { + IntentEvent event = events.hasNext() ? events.next() : null; + if (event == null) { + fail("expected event not found: " + type); + } else if (intent.equals(event.subject())) { + assertEquals("incorrect state", type, event.type()); + } + } + + // Remainder of events should not apply to this intent; make sure. + while (events.hasNext()) { + assertFalse("unexpected event for intent", + intent.equals(events.next().subject())); + } + } + + @Test + public void compilerBasics() { + // Make sure there are no compilers + assertEquals("incorrect compiler count", 0, service.getCompilers().size()); + + // Add a compiler and make sure that it appears in the map + IntentCompiler compiler = new TestCompiler(false); + service.registerCompiler(TestIntent.class, compiler); + assertEquals("incorrect compiler", compiler, + service.getCompilers().get(TestIntent.class)); + + // Remove the same and make sure that it no longer appears in the map + service.unregisterCompiler(TestIntent.class); + assertNull("compiler should not be registered", + service.getCompilers().get(TestIntent.class)); + } + + @Test + public void implicitRegistration() { + // Add a compiler and make sure that it appears in the map + IntentCompiler compiler = new TestCompiler(new TestSubclassInstallableIntent(INSTALLABLE_IID)); + service.registerCompiler(TestIntent.class, compiler); + assertEquals("incorrect compiler", compiler, + service.getCompilers().get(TestIntent.class)); + + // Submit an intent which is a subclass of the one we registered + final Intent intent = new TestSubclassIntent(IID); + service.submit(intent); + + // Allow some time for the intent to be compiled and installed + TestTools.assertAfter(GRACE_MS, new Runnable() { + @Override + public void run() { + assertEquals("incorrect intent state", IntentState.INSTALLED, + service.getIntentState(intent.key())); + } + }); + + // Make sure that now we have an implicit registration of the compiler + // under the intent subclass + assertEquals("incorrect compiler", compiler, + service.getCompilers().get(TestSubclassIntent.class)); + + // TODO: discuss whether or if implicit registration should require implicit unregistration + // perhaps unregister by compiler or installer itself, rather than by class would be better + } + + + // Fixture to track emitted intent events + protected class TestListener implements IntentListener { + final List events = new ArrayList<>(); + + @Override + public void event(IntentEvent event) { + events.add(event); + } + } + + // Controllable compiler + private class TestCompiler implements IntentCompiler { + private final boolean fail; + private final List result; + + TestCompiler(boolean fail) { + this.fail = fail; + this.result = Collections.emptyList(); + } + + TestCompiler(Intent... result) { + this.fail = false; + this.result = Arrays.asList(result); + } + + @Override + public List compile(TestIntent intent, List installable, + Set resources) { + if (fail) { + throw new IntentException("compile failed by design"); + } + List compiled = new ArrayList<>(result); + return compiled; + } + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTest.java new file mode 100644 index 00000000..d713b8aa --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTest.java @@ -0,0 +1,52 @@ +/* + * Copyright 2014 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.intent; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * Base facilities to test various intent tests. + */ +public abstract class IntentTest extends AbstractIntentTest { + /** + * Produces a set of items from the supplied items. + * + * @param items items to be placed in set + * @param item type + * @return set of items + */ + protected static Set itemSet(T[] items) { + return new HashSet<>(Arrays.asList(items)); + } + + /** + * Creates a new intent, but always a like intent, i.e. all instances will + * be equal, but should not be the same. + * + * @return intent + */ + protected abstract Intent createOne(); + + /** + * Creates another intent, not equals to the one created by + * {@link #createOne()} and with a different hash code. + * + * @return another intent + */ + protected abstract Intent createAnother(); +} 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 new file mode 100644 index 00000000..ac4ecff3 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java @@ -0,0 +1,496 @@ +/* + * Copyright 2014-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.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; +import org.onosproject.net.DeviceId; +import org.onosproject.net.ElementId; +import org.onosproject.net.Link; +import org.onosproject.net.NetTestTools; +import org.onosproject.net.NetworkResource; +import org.onosproject.net.Path; +import org.onosproject.net.flow.FlowId; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.FlowRuleExtPayLoad; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.criteria.Criterion; +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.link.BandwidthResource; +import org.onosproject.net.resource.link.BandwidthResourceRequest; +import org.onosproject.net.resource.link.LambdaResource; +import org.onosproject.net.resource.link.LambdaResourceAllocation; +import org.onosproject.net.resource.link.LambdaResourceRequest; +import org.onosproject.net.resource.link.LinkResourceAllocations; +import org.onosproject.net.resource.link.LinkResourceListener; +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.TopologyVertex; +import org.onosproject.store.Timestamp; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +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; + +/** + * Common mocks used by the intent framework tests. + */ +public class IntentTestsMocks { + /** + * Mock traffic selector class used for satisfying API requirements. + */ + public static class MockSelector implements TrafficSelector { + @Override + public Set criteria() { + return new HashSet<>(); + } + + @Override + public Criterion getCriterion(Type type) { + return null; + } + } + + /** + * Mock traffic treatment class used for satisfying API requirements. + */ + public static class MockTreatment implements TrafficTreatment { + @Override + public List deferred() { + return Collections.emptyList(); + } + + @Override + public List immediate() { + return Collections.emptyList(); + } + + @Override + public List allInstructions() { + return Collections.emptyList(); + } + + @Override + public Instructions.TableTypeTransition tableTransition() { + return null; + } + + @Override + public boolean clearedDeferred() { + return false; + } + + @Override + public MetadataInstruction writeMetadata() { + return null; + } + + @Override + public Instructions.MeterInstruction metered() { + return null; + } + } + + /** + * Mock path service for creating paths within the test. + */ + public static class MockPathService implements PathService { + + final String[] pathHops; + final String[] reversePathHops; + + /** + * Constructor that provides a set of hops to mock. + * + * @param pathHops path hops to mock + */ + public MockPathService(String[] pathHops) { + this.pathHops = pathHops; + String[] reversed = pathHops.clone(); + Collections.reverse(Arrays.asList(reversed)); + reversePathHops = reversed; + } + + @Override + public Set getPaths(ElementId src, ElementId dst) { + Set result = new HashSet<>(); + + String[] allHops = new String[pathHops.length]; + + if (src.toString().endsWith(pathHops[0])) { + System.arraycopy(pathHops, 0, allHops, 0, pathHops.length); + } else { + System.arraycopy(reversePathHops, 0, allHops, 0, pathHops.length); + } + + result.add(createPath(allHops)); + return result; + } + + @Override + public Set getPaths(ElementId src, ElementId dst, LinkWeight weight) { + final Set paths = getPaths(src, dst); + + for (Path path : paths) { + final DeviceId srcDevice = path.src().deviceId(); + final DeviceId dstDevice = path.dst().deviceId(); + final TopologyVertex srcVertex = new DefaultTopologyVertex(srcDevice); + final TopologyVertex dstVertex = new DefaultTopologyVertex(dstDevice); + final Link link = link(src.toString(), 1, dst.toString(), 1); + + final double weightValue = weight.weight(new DefaultTopologyEdge(srcVertex, dstVertex, link)); + if (weightValue < 0) { + return new HashSet<>(); + } + } + return paths; + } + } + + public static class MockLinkResourceAllocations implements LinkResourceAllocations { + @Override + public Set getResourceAllocation(Link link) { + return ImmutableSet.of( + new LambdaResourceAllocation(LambdaResource.valueOf(77)), + new MplsLabelResourceAllocation(MplsLabel.valueOf(10))); + } + + public IntentId intentId() { + return null; + } + + public Collection links() { + return null; + } + + public Set resources() { + return null; + } + + @Override + public ResourceType type() { + return null; + } + } + + public static class MockedAllocationFailure extends RuntimeException { } + + public static class MockResourceService implements LinkResourceService { + + double availableBandwidth = -1.0; + int availableLambda = -1; + + /** + * Allocates a resource service that will allow bandwidth allocations + * up to a limit. + * + * @param bandwidth available bandwidth limit + * @return resource manager for bandwidth requests + */ + public static MockResourceService makeBandwidthResourceService(double bandwidth) { + final MockResourceService result = new MockResourceService(); + result.availableBandwidth = bandwidth; + return result; + } + + /** + * Allocates a resource service that will allow lambda allocations. + * + * @param lambda Lambda to return for allocation requests. Currently unused + * @return resource manager for lambda requests + */ + public static MockResourceService makeLambdaResourceService(int lambda) { + final MockResourceService result = new MockResourceService(); + result.availableLambda = lambda; + return result; + } + + public void setAvailableBandwidth(double availableBandwidth) { + this.availableBandwidth = availableBandwidth; + } + + public void setAvailableLambda(int availableLambda) { + this.availableLambda = availableLambda; + } + + + @Override + public LinkResourceAllocations requestResources(LinkResourceRequest req) { + int lambda = -1; + double bandwidth = -1.0; + + for (ResourceRequest resourceRequest : req.resources()) { + if (resourceRequest.type() == ResourceType.BANDWIDTH) { + final BandwidthResourceRequest brr = (BandwidthResourceRequest) resourceRequest; + bandwidth = brr.bandwidth().toDouble(); + } else if (resourceRequest.type() == ResourceType.LAMBDA) { + lambda = 1; + } + } + + if (availableBandwidth < bandwidth) { + throw new MockedAllocationFailure(); + } + if (lambda > 0 && availableLambda == 0) { + throw new MockedAllocationFailure(); + } + + return new IntentTestsMocks.MockLinkResourceAllocations(); + } + + @Override + public void releaseResources(LinkResourceAllocations allocations) { + // Mock + } + + @Override + public LinkResourceAllocations updateResources(LinkResourceRequest req, + LinkResourceAllocations oldAllocations) { + return null; + } + + @Override + public Iterable getAllocations() { + return ImmutableSet.of( + new IntentTestsMocks.MockLinkResourceAllocations()); + } + + @Override + public Iterable getAllocations(Link link) { + return ImmutableSet.of( + new IntentTestsMocks.MockLinkResourceAllocations()); + } + + @Override + public LinkResourceAllocations getAllocations(IntentId intentId) { + return new IntentTestsMocks.MockLinkResourceAllocations(); + } + + @Override + public Iterable getAvailableResources(Link link) { + final List result = new LinkedList<>(); + if (availableBandwidth > 0.0) { + result.add(new BandwidthResourceRequest( + new BandwidthResource(Bandwidth.bps(availableBandwidth)))); + } + if (availableLambda > 0) { + result.add(new LambdaResourceRequest()); + } + return result; + } + + @Override + public Iterable getAvailableResources(Link link, LinkResourceAllocations allocations) { + return null; + } + + @Override + public void addListener(LinkResourceListener listener) { + + } + + @Override + public void removeListener(LinkResourceListener listener) { + + } + } + + private static final IntentTestsMocks.MockSelector SELECTOR = + new IntentTestsMocks.MockSelector(); + private static final IntentTestsMocks.MockTreatment TREATMENT = + new IntentTestsMocks.MockTreatment(); + + public static class MockFlowRule implements FlowRule { + static int nextId = 0; + + int priority; + int tableId; + long timestamp; + int id; + FlowRuleExtPayLoad payLoad; + + public MockFlowRule(int priority) { + this.priority = priority; + this.tableId = 0; + this.timestamp = System.currentTimeMillis(); + this.id = nextId++; + this.payLoad = null; + } + + public MockFlowRule(int priority, FlowRuleExtPayLoad payLoad) { + this.priority = priority; + this.timestamp = System.currentTimeMillis(); + this.id = nextId++; + this.payLoad = payLoad; + } + + @Override + public FlowId id() { + return FlowId.valueOf(id); + } + + @Override + public short appId() { + return 0; + } + + @Override + public GroupId groupId() { + return new DefaultGroupId(0); + } + + @Override + public int priority() { + return priority; + } + + @Override + public DeviceId deviceId() { + return did("1"); + } + + @Override + public TrafficSelector selector() { + return SELECTOR; + } + + @Override + public TrafficTreatment treatment() { + return TREATMENT; + } + + @Override + public int timeout() { + return 0; + } + + @Override + public boolean isPermanent() { + return false; + } + + @Override + public int hashCode() { + return Objects.hash(priority); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final MockFlowRule other = (MockFlowRule) obj; + return Objects.equals(this.timestamp, other.timestamp) && + this.id == other.id; + } + + @Override + public boolean exactMatch(FlowRule rule) { + return this.equals(rule); + } + + @Override + public int tableId() { + return tableId; + } + + @Override + public FlowRuleExtPayLoad payLoad() { + return payLoad; + } + } + + public static class MockIntent extends Intent { + private static AtomicLong counter = new AtomicLong(0); + + private final Long number; + + public MockIntent(Long number) { + super(NetTestTools.APP_ID, null, Collections.emptyList(), + Intent.DEFAULT_INTENT_PRIORITY); + this.number = number; + } + + public MockIntent(Long number, Collection resources) { + super(NetTestTools.APP_ID, null, resources, Intent.DEFAULT_INTENT_PRIORITY); + this.number = number; + } + + public Long number() { + return number; + } + + public static Long nextId() { + return counter.getAndIncrement(); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("id", id()) + .add("appId", appId()) + .toString(); + } + } + + public static class MockTimestamp implements Timestamp { + final int value; + + public MockTimestamp(int value) { + this.value = value; + } + + @Override + public int compareTo(Timestamp o) { + if (!(o instanceof MockTimestamp)) { + return -1; + } + MockTimestamp that = (MockTimestamp) o; + return this.value - that.value; + } + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/KeyTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/KeyTest.java new file mode 100644 index 00000000..dfc73442 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/KeyTest.java @@ -0,0 +1,121 @@ +/* + * 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.intent; + +import org.junit.Test; +import org.onosproject.net.NetTestTools; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBaseClass; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +/** + * Unit tests for the intent key class. + */ +public class KeyTest { + + private static final String KEY_1 = "key1"; + private static final String KEY_2 = "key2"; + private static final String KEY_3 = "key3"; + + private static final long LONG_KEY_1 = 0x1111; + private static final long LONG_KEY_2 = 0x2222; + private static final long LONG_KEY_3 = 0x3333; + + /** + * Tests that keys are properly immutable. + */ + @Test + public void keysAreImmutable() { + assertThatClassIsImmutableBaseClass(Key.class); + + // Will be a long based key, class is private so cannot be + // accessed directly + Key longKey = Key.of(0xabcdefL, NetTestTools.APP_ID); + assertThatClassIsImmutable(longKey.getClass()); + + // Will be a String based key, class is private so cannot be + // accessed directly. + Key stringKey = Key.of("some key", NetTestTools.APP_ID); + assertThatClassIsImmutable(stringKey.getClass()); + } + + /** + * Tests string key construction. + */ + @Test + public void stringKeyConstruction() { + Key stringKey1 = Key.of(KEY_3, NetTestTools.APP_ID); + assertThat(stringKey1, notNullValue()); + Key stringKey2 = Key.of(KEY_3, NetTestTools.APP_ID); + assertThat(stringKey2, notNullValue()); + + assertThat(stringKey1.hash(), is(stringKey2.hash())); + } + + /** + * Tests long key construction. + */ + @Test + public void longKeyConstruction() { + Key longKey1 = Key.of(LONG_KEY_3, NetTestTools.APP_ID); + assertThat(longKey1, notNullValue()); + Key longKey2 = Key.of(LONG_KEY_3, NetTestTools.APP_ID); + assertThat(longKey2, notNullValue()); + + assertThat(longKey1.hash(), is(longKey2.hash())); + } + + /** + * Tests equals for string based keys. + */ + @Test + public void stringKey() { + Key stringKey1 = Key.of(KEY_1, NetTestTools.APP_ID); + Key copyOfStringKey1 = Key.of(KEY_1, NetTestTools.APP_ID); + Key stringKey2 = Key.of(KEY_2, NetTestTools.APP_ID); + Key copyOfStringKey2 = Key.of(KEY_2, NetTestTools.APP_ID); + Key stringKey3 = Key.of(KEY_3, NetTestTools.APP_ID); + + new EqualsTester() + .addEqualityGroup(stringKey1, copyOfStringKey1) + .addEqualityGroup(stringKey2, copyOfStringKey2) + .addEqualityGroup(stringKey3) + .testEquals(); + } + + /** + * Tests equals for long based keys. + */ + @Test + public void longKey() { + Key longKey1 = Key.of(LONG_KEY_1, NetTestTools.APP_ID); + Key copyOfLongKey1 = Key.of(LONG_KEY_1, NetTestTools.APP_ID); + Key longKey2 = Key.of(LONG_KEY_2, NetTestTools.APP_ID); + Key copyOfLongKey2 = Key.of(LONG_KEY_2, NetTestTools.APP_ID); + Key longKey3 = Key.of(LONG_KEY_3, NetTestTools.APP_ID); + + new EqualsTester() + .addEqualityGroup(longKey1, copyOfLongKey1) + .addEqualityGroup(longKey2, copyOfLongKey2) + .addEqualityGroup(longKey3) + .testEquals(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/LinkCollectionIntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/LinkCollectionIntentTest.java new file mode 100644 index 00000000..88fa7f4f --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/LinkCollectionIntentTest.java @@ -0,0 +1,209 @@ +/* + * Copyright 2014-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.intent; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import org.junit.Test; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Link; +import org.onosproject.net.NetTestTools; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.intent.constraint.LambdaConstraint; +import org.onosproject.net.resource.link.LambdaResource; + +import com.google.common.collect.ImmutableSet; +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.startsWith; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.net.NetTestTools.APP_ID; +import static org.onosproject.net.NetTestTools.link; + +/** + * Unit tests for the LinkCollectionIntent class. + */ +public class LinkCollectionIntentTest extends IntentTest { + + final ConnectPoint ingress = NetTestTools.connectPoint("ingress", 2); + final ConnectPoint egress = NetTestTools.connectPoint("egress", 3); + final TrafficSelector selector = new IntentTestsMocks.MockSelector(); + final IntentTestsMocks.MockTreatment treatment = new IntentTestsMocks.MockTreatment(); + + /** + * Checks that the LinkCollectionIntent class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(LinkCollectionIntent.class); + } + + /** + * Tests equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + + final HashSet links1 = new HashSet<>(); + links1.add(link("src", 1, "dst", 2)); + final LinkCollectionIntent collectionIntent1 = + LinkCollectionIntent.builder() + .appId(APP_ID) + .selector(selector) + .treatment(treatment) + .links(links1) + .ingressPoints(ImmutableSet.of(ingress)) + .egressPoints(ImmutableSet.of(egress)) + .build(); + + final HashSet links2 = new HashSet<>(); + links2.add(link("src", 1, "dst", 3)); + final LinkCollectionIntent collectionIntent2 = + LinkCollectionIntent.builder() + .appId(APP_ID) + .selector(selector) + .treatment(treatment) + .links(links2) + .ingressPoints(ImmutableSet.of(ingress)) + .egressPoints(ImmutableSet.of(egress)) + .build(); + + new EqualsTester() + .addEqualityGroup(collectionIntent1) + .addEqualityGroup(collectionIntent2) + .testEquals(); + } + + /** + * Tests constructor without constraints. + */ + @Test + public void testConstructor() { + final HashSet links1 = new HashSet<>(); + links1.add(link("src", 1, "dst", 2)); + final LinkCollectionIntent collectionIntent = + LinkCollectionIntent.builder() + .appId(APP_ID) + .selector(selector) + .treatment(treatment) + .links(links1) + .ingressPoints(ImmutableSet.of(ingress)) + .egressPoints(ImmutableSet.of(egress)) + .build(); + + final Set createdLinks = collectionIntent.links(); + assertThat(createdLinks, hasSize(1)); + assertThat(collectionIntent.isInstallable(), is(false)); + assertThat(collectionIntent.treatment(), is(treatment)); + assertThat(collectionIntent.selector(), is(selector)); + assertThat(collectionIntent.ingressPoints(), is(ImmutableSet.of(ingress))); + assertThat(collectionIntent.egressPoints(), is(ImmutableSet.of(egress))); + assertThat(collectionIntent.resources(), hasSize(1)); + final List createdConstraints = collectionIntent.constraints(); + assertThat(createdConstraints, hasSize(0)); + } + + /** + * Tests constructor with constraints. + */ + @Test + public void testConstructorWithConstraints() { + final HashSet links1 = new HashSet<>(); + final LinkedList constraints = new LinkedList<>(); + + links1.add(link("src", 1, "dst", 2)); + constraints.add(new LambdaConstraint(LambdaResource.valueOf(23))); + final LinkCollectionIntent collectionIntent = + LinkCollectionIntent.builder() + .appId(APP_ID) + .selector(selector) + .treatment(treatment) + .links(links1) + .ingressPoints(ImmutableSet.of(ingress)) + .egressPoints(ImmutableSet.of(egress)) + .constraints(constraints) + .priority(8888) + .build(); + + final Set createdLinks = collectionIntent.links(); + assertThat(createdLinks, hasSize(1)); + assertThat(collectionIntent.isInstallable(), is(false)); + assertThat(collectionIntent.treatment(), is(treatment)); + assertThat(collectionIntent.selector(), is(selector)); + assertThat(collectionIntent.ingressPoints(), is(ImmutableSet.of(ingress))); + assertThat(collectionIntent.egressPoints(), is(ImmutableSet.of(egress))); + + final List createdConstraints = collectionIntent.constraints(); + assertThat(createdConstraints, hasSize(1)); + assertThat(createdConstraints.get(0).toString(), startsWith("LambdaConstraint")); + } + + /** + * Tests constructor with constraints. + */ + @Test + public void testSerializerConstructor() { + + final LinkCollectionIntent collectionIntent = + new LinkCollectionIntent(); + + final Set createdLinks = collectionIntent.links(); + assertThat(createdLinks, nullValue()); + assertThat(collectionIntent.isInstallable(), is(false)); + assertThat(collectionIntent.treatment(), nullValue()); + assertThat(collectionIntent.selector(), nullValue()); + assertThat(collectionIntent.ingressPoints(), nullValue()); + assertThat(collectionIntent.egressPoints(), nullValue()); + + final List createdConstraints = collectionIntent.constraints(); + assertThat(createdConstraints, hasSize(0)); + } + + @Override + protected Intent createOne() { + HashSet links1 = new HashSet<>(); + links1.add(link("src", 1, "dst", 2)); + return LinkCollectionIntent.builder() + .appId(APP_ID) + .selector(selector) + .treatment(treatment) + .links(links1) + .ingressPoints(ImmutableSet.of(ingress)) + .egressPoints(ImmutableSet.of(egress)) + .build(); + } + + @Override + protected Intent createAnother() { + HashSet links2 = new HashSet<>(); + links2.add(link("src", 1, "dst", 3)); + return LinkCollectionIntent.builder() + .appId(APP_ID) + .selector(selector) + .treatment(treatment) + .links(links2) + .ingressPoints(ImmutableSet.of(ingress)) + .egressPoints(ImmutableSet.of(egress)) + .build(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MockIdGenerator.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MockIdGenerator.java new file mode 100644 index 00000000..5e84cd8c --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MockIdGenerator.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014 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.intent; + +import org.onosproject.core.IdGenerator; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * Mock id generator for testing. + */ +public class MockIdGenerator implements IdGenerator { + private AtomicLong nextId = new AtomicLong(0); + + @Override + public long getNewId() { + return nextId.getAndIncrement(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MplsIntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MplsIntentTest.java new file mode 100644 index 00000000..196d6ad4 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MplsIntentTest.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.intent; + +import java.util.Optional; + +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.MplsLabel; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.net.NetTestTools.APP_ID; +import static org.onosproject.net.NetTestTools.connectPoint; + +/** + * Unit tests for the MplsIntent class. + */ + +public class MplsIntentTest extends AbstractIntentTest { + static final int PRIORITY = 22; + + MplsIntent intent1; + MplsIntent intent2; + + Optional label1; + Optional label2; + + TrafficSelector selector; + TrafficTreatment treatment; + + @Before + public void mplsIntentTestSetUp() throws Exception { + + label1 = Optional.of(MplsLabel.mplsLabel(1)); + label2 = Optional.of(MplsLabel.mplsLabel(2)); + + selector = new IntentTestsMocks.MockSelector(); + treatment = new IntentTestsMocks.MockTreatment(); + + intent1 = MplsIntent.builder() + .appId(APP_ID) + .ingressLabel(label1) + .egressLabel(label2) + .ingressPoint(connectPoint("in", 1)) + .egressPoint(connectPoint("out", 1)) + .selector(selector) + .treatment(treatment) + .priority(PRIORITY) + .build(); + + intent2 = MplsIntent.builder() + .appId(APP_ID) + .ingressLabel(label1) + .egressLabel(label2) + .ingressPoint(connectPoint("in", 2)) + .egressPoint(connectPoint("out", 2)) + .selector(selector) + .treatment(treatment) + .priority(PRIORITY) + .build(); + } + + /** + * Checks that the MplsIntent class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(MplsIntent.class); + } + + /** + * Checks the operation of equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(intent1) + .addEqualityGroup(intent2) + .testEquals(); + } + + /** + * Checks that the MplsIntent objects are created correctly. + */ + @Test + public void testContents() { + assertThat(intent1.appId(), equalTo(APP_ID)); + assertThat(intent1.ingressLabel(), equalTo(label1)); + assertThat(intent1.egressLabel(), equalTo(label2)); + assertThat(intent1.ingressPoint(), equalTo(connectPoint("in", 1))); + assertThat(intent1.egressPoint(), equalTo(connectPoint("out", 1))); + assertThat(intent1.selector(), equalTo(intent2.selector())); + assertThat(intent1.treatment(), equalTo(intent2.treatment())); + assertThat(intent1.priority(), is(PRIORITY)); + + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MplsPathIntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MplsPathIntentTest.java new file mode 100644 index 00000000..551f19eb --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MplsPathIntentTest.java @@ -0,0 +1,110 @@ +/* + * 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.intent; + +import java.util.Optional; + +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.MplsLabel; +import org.onosproject.net.Path; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.net.NetTestTools.APP_ID; +import static org.onosproject.net.NetTestTools.createPath; + +/** + * Unit tests for the MplsPathIntent class. + */ +public class MplsPathIntentTest extends AbstractIntentTest { + + static final int PRIORITY = 777; + + MplsPathIntent intent1; + MplsPathIntent intent2; + Path defaultPath; + Optional label1; + Optional label2; + TrafficSelector selector; + TrafficTreatment treatment; + + @Before + public void mplsPathIntentTestSetUp() { + defaultPath = createPath("a", "b", "c"); + selector = new IntentTestsMocks.MockSelector(); + treatment = new IntentTestsMocks.MockTreatment(); + + label1 = Optional.of(MplsLabel.mplsLabel(1)); + label2 = Optional.of(MplsLabel.mplsLabel(2)); + intent1 = MplsPathIntent.builder() + .appId(APP_ID) + .ingressLabel(label1) + .egressLabel(label2) + .path(defaultPath) + .priority(PRIORITY) + .build(); + + intent2 = MplsPathIntent.builder() + .appId(APP_ID) + .ingressLabel(label1) + .egressLabel(label2) + .path(defaultPath) + .priority(PRIORITY) + .build(); + } + + + /** + * Checks that the MplsPathIntent class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(MplsPathIntent.class); + } + + /** + * Checks the operation of equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(intent1) + .addEqualityGroup(intent2) + .testEquals(); + } + + /** + * Checks that the MPLS path intent objects are created correctly. + */ + @Test + public void testContents() { + assertThat(intent1.appId(), equalTo(APP_ID)); + assertThat(intent1.ingressLabel(), equalTo(label1)); + assertThat(intent1.egressLabel(), equalTo(label2)); + assertThat(intent1.selector(), equalTo(intent2.selector())); + assertThat(intent1.treatment(), equalTo(intent2.treatment())); + assertThat(intent1.priority(), is(PRIORITY)); + assertThat(intent1.path(), is(defaultPath)); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MultiPointToSinglePointIntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MultiPointToSinglePointIntentTest.java new file mode 100644 index 00000000..00be3101 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/MultiPointToSinglePointIntentTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2014-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.intent; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +/** + * Suite of tests of the multi-to-single point intent descriptor. + */ +public class MultiPointToSinglePointIntentTest extends ConnectivityIntentTest { + + /** + * Checks that the MultiPointToSinglePointIntent class is immutable. + */ + @Test + public void checkImmutability() { + assertThatClassIsImmutable(MultiPointToSinglePointIntent.class); + } + + @Test + public void basics() { + MultiPointToSinglePointIntent intent = createOne(); + assertEquals("incorrect id", APPID, intent.appId()); + assertEquals("incorrect match", MATCH, intent.selector()); + assertEquals("incorrect ingress", PS1, intent.ingressPoints()); + assertEquals("incorrect egress", P2, intent.egressPoint()); + } + + @Override + protected MultiPointToSinglePointIntent createOne() { + return MultiPointToSinglePointIntent.builder() + .appId(APPID) + .selector(MATCH) + .treatment(NOP) + .ingressPoints(PS1) + .egressPoint(P2) + .build(); + } + + @Override + protected MultiPointToSinglePointIntent createAnother() { + return MultiPointToSinglePointIntent.builder() + .appId(APPID) + .selector(MATCH) + .treatment(NOP) + .ingressPoints(PS2) + .egressPoint(P1) + .build(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/OpticalConnectivityIntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/OpticalConnectivityIntentTest.java new file mode 100644 index 00000000..7df220c3 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/OpticalConnectivityIntentTest.java @@ -0,0 +1,35 @@ +/* + * 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.intent; + +import org.junit.Test; + +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +/** + * Unit tests for the OpticalConnectivityIntent class. + */ +public class OpticalConnectivityIntentTest { + + /** + * Checks that the HostToHostIntent class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(OpticalConnectivityIntent.class); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/OpticalPathIntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/OpticalPathIntentTest.java new file mode 100644 index 00000000..36e018a9 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/OpticalPathIntentTest.java @@ -0,0 +1,97 @@ +/* + * 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.intent; + +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.net.OchSignalType; +import org.onosproject.net.Path; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.net.NetTestTools.APP_ID; +import static org.onosproject.net.NetTestTools.connectPoint; +import static org.onosproject.net.NetTestTools.createLambda; +import static org.onosproject.net.NetTestTools.createPath; + +public class OpticalPathIntentTest extends AbstractIntentTest { + + static final int PRIORITY = 777; + + OpticalPathIntent intent1; + OpticalPathIntent intent2; + Path defaultPath; + + @Before + public void opticalPathIntentTestSetUp() { + defaultPath = createPath("a", "b", "c"); + intent1 = OpticalPathIntent.builder() + .appId(APP_ID) + .src(connectPoint("one", 1)) + .dst(connectPoint("two", 2)) + .path(defaultPath) + .lambda(createLambda()) + .signalType(OchSignalType.FIXED_GRID) + .priority(PRIORITY) + .build(); + + intent2 = OpticalPathIntent.builder() + .appId(APP_ID) + .src(connectPoint("two", 1)) + .dst(connectPoint("one", 2)) + .path(defaultPath) + .lambda(createLambda()) + .signalType(OchSignalType.FIXED_GRID) + .priority(PRIORITY) + .build(); + } + + /** + * Checks that the OpticalPathIntent class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(OpticalPathIntent.class); + } + + /** + * Checks the operation of equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(intent1) + .addEqualityGroup(intent2) + .testEquals(); + } + + /** + * Checks that the optical path intent objects are created correctly. + */ + @Test + public void testContents() { + assertThat(intent1.appId(), equalTo(APP_ID)); + assertThat(intent1.src(), Matchers.equalTo(connectPoint("one", 1))); + assertThat(intent1.dst(), Matchers.equalTo(connectPoint("two", 2))); + assertThat(intent1.priority(), is(PRIORITY)); + assertThat(intent1.path(), is(defaultPath)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/PartitionServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/PartitionServiceAdapter.java new file mode 100644 index 00000000..ffb2635e --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/PartitionServiceAdapter.java @@ -0,0 +1,45 @@ +/* + * 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.intent; + +import org.onosproject.cluster.NodeId; + +import static org.junit.Assert.*; + +/** + * Testing adapter for the partition service. + */ +public class PartitionServiceAdapter implements PartitionService { + @Override + public boolean isMine(Key intentKey) { + return true; + } + + @Override + public NodeId getLeader(Key intentKey) { + return null; + } + + @Override + public void addListener(PartitionEventListener listener) { + + } + + @Override + public void removeListener(PartitionEventListener listener) { + + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/PathIntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/PathIntentTest.java new file mode 100644 index 00000000..dfbc1846 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/PathIntentTest.java @@ -0,0 +1,115 @@ +/* + * Copyright 2014-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.intent; + +import java.util.Arrays; +import java.util.Collections; + +import org.junit.Test; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultLink; +import org.onosproject.net.DefaultPath; +import org.onosproject.net.DeviceId; +import org.onosproject.net.NetTestTools; +import org.onosproject.net.Path; +import org.onosproject.net.PortNumber; +import org.onosproject.net.provider.ProviderId; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.Link.Type.DIRECT; +import static org.onosproject.net.PortNumber.portNumber; + +public class PathIntentTest extends ConnectivityIntentTest { + // 111:11 --> 222:22 + private static final Path PATH1 = NetTestTools.createPath("111", "222"); + + // 111:11 --> 333:33 + private static final Path PATH2 = NetTestTools.createPath("222", "333"); + + private final ProviderId provider1 = new ProviderId("of", "1"); + private final DeviceId device1 = deviceId("1"); + private final DeviceId device2 = deviceId("2"); + private final PortNumber port1 = portNumber(1); + private final PortNumber port2 = portNumber(2); + private final PortNumber port3 = portNumber(3); + private final PortNumber port4 = portNumber(4); + private final ConnectPoint cp1 = new ConnectPoint(device1, port1); + private final ConnectPoint cp2 = new ConnectPoint(device1, port2); + private final ConnectPoint cp3 = new ConnectPoint(device2, port3); + private final ConnectPoint cp4 = new ConnectPoint(device2, port4); + private final DefaultLink link1 = new DefaultLink(provider1, cp1, cp2, DIRECT); + private final DefaultLink link2 = new DefaultLink(provider1, cp1, cp2, DIRECT); + private final double cost = 1; + + @Test + public void basics() { + PathIntent intent = createOne(); + assertEquals("incorrect id", APPID, intent.appId()); + assertEquals("incorrect match", MATCH, intent.selector()); + assertEquals("incorrect action", NOP, intent.treatment()); + assertEquals("incorrect path", PATH1, intent.path()); + } + + @Override + protected PathIntent createOne() { + return PathIntent.builder() + .appId(APPID) + .selector(MATCH) + .treatment(NOP) + .path(PATH1) + .build(); + } + + @Override + protected PathIntent createAnother() { + return PathIntent.builder() + .appId(APPID) + .selector(MATCH) + .treatment(NOP) + .path(PATH2) + .build(); + } + + /** + * Tests the constructor raises IllegalArgumentException when the same device is specified in + * source and destination of a link. + */ + @Test(expected = IllegalArgumentException.class) + public void testRaiseExceptionWhenSameDevices() { + PathIntent.builder() + .appId(APPID) + .selector(MATCH) + .treatment(NOP) + .path(new DefaultPath(provider1, Collections.singletonList(link1), cost)) + .build(); + } + + /** + * Tests the constructor raises IllegalArgumentException when the different elements are specified + * in source element of the first link and destination element of the second link. + */ + @Test(expected = IllegalArgumentException.class) + public void testRaiseExceptionWhenDifferentDevice() { + PathIntent.builder() + .appId(APPID) + .selector(MATCH) + .treatment(NOP) + .path(new DefaultPath(provider1, Arrays.asList(link1, link2), cost)) + .build(); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java new file mode 100644 index 00000000..46772f9f --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2014-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.intent; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBaseClass; + +/** + * Suite of tests of the point-to-point intent descriptor. + */ +public class PointToPointIntentTest extends ConnectivityIntentTest { + + /** + * Checks that the MultiPointToSinglePointIntent class is immutable. + */ + @Test + public void checkImmutability() { + assertThatClassIsImmutableBaseClass(PointToPointIntent.class); + } + + @Test + public void basics() { + PointToPointIntent intent = createOne(); + assertEquals("incorrect id", APPID, intent.appId()); + assertEquals("incorrect match", MATCH, intent.selector()); + assertEquals("incorrect ingress", P1, intent.ingressPoint()); + assertEquals("incorrect egress", P2, intent.egressPoint()); + } + + @Override + protected PointToPointIntent createOne() { + return PointToPointIntent.builder() + .appId(APPID) + .selector(MATCH) + .treatment(NOP) + .ingressPoint(P1) + .egressPoint(P2) + .build(); + } + + @Override + protected PointToPointIntent createAnother() { + return PointToPointIntent.builder() + .appId(APPID) + .selector(MATCH) + .treatment(NOP) + .ingressPoint(P2) + .egressPoint(P1) + .build(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/SinglePointToMultiPointIntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/SinglePointToMultiPointIntentTest.java new file mode 100644 index 00000000..18c6d7bc --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/SinglePointToMultiPointIntentTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2014-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.intent; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +/** + * Suite of tests of the single-to-multi point intent descriptor. + */ +public class SinglePointToMultiPointIntentTest extends ConnectivityIntentTest { + + /** + * Checks that the SinglePointToMultiPointIntent class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(SinglePointToMultiPointIntent.class); + } + + @Test + public void basics() { + SinglePointToMultiPointIntent intent = createOne(); + assertEquals("incorrect id", APPID, intent.appId()); + assertEquals("incorrect match", MATCH, intent.selector()); + assertEquals("incorrect ingress", P1, intent.ingressPoint()); + assertEquals("incorrect egress", PS2, intent.egressPoints()); + } + + @Override + protected SinglePointToMultiPointIntent createOne() { + return SinglePointToMultiPointIntent.builder() + .appId(APPID) + .selector(MATCH) + .treatment(NOP) + .ingressPoint(P1) + .egressPoints(PS2) + .build(); + } + + @Override + protected SinglePointToMultiPointIntent createAnother() { + return SinglePointToMultiPointIntent.builder() + .appId(APPID) + .selector(MATCH) + .treatment(NOP) + .ingressPoint(P2) + .egressPoints(PS1) + .build(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestInstallableIntent.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestInstallableIntent.java new file mode 100644 index 00000000..d949ee16 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestInstallableIntent.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014-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.intent; + +import org.onosproject.TestApplicationId; + +import java.util.Collections; + +/** + * An installable intent used in the unit test. + */ +public class TestInstallableIntent extends Intent { + + private final int value; + + /** + * Constructs an instance with the specified intent ID. + * + * @param value intent ID + */ + public TestInstallableIntent(int value) { // FIXME + super(new TestApplicationId("foo"), null, Collections.emptyList(), + Intent.DEFAULT_INTENT_PRIORITY); + this.value = value; + } + + /** + * Constructor for serializer. + */ + protected TestInstallableIntent() { + super(); + value = -1; + } + + @Override + public boolean isInstallable() { + return true; + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestIntent.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestIntent.java new file mode 100644 index 00000000..857fc8b5 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestIntent.java @@ -0,0 +1,47 @@ +/* + * Copyright 2014-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.intent; + +import org.onosproject.TestApplicationId; + +import java.util.Collections; + +/** + * An intent used in the unit test. + */ +public class TestIntent extends Intent { + + private final int value; + + /** + * Constructs an instance with the specified intent ID. + * + * @param value intent ID + */ + public TestIntent(int value) { // FIXME + super(new TestApplicationId("foo"), null, Collections.emptyList(), + Intent.DEFAULT_INTENT_PRIORITY); + this.value = value; + } + + /** + * Constructor for serializer. + */ + protected TestIntent() { + super(); + value = -1; + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestSubclassInstallableIntent.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestSubclassInstallableIntent.java new file mode 100644 index 00000000..82c14843 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestSubclassInstallableIntent.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 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.intent; + +/** + * An intent used in the unit test. + */ +public class TestSubclassInstallableIntent extends TestInstallableIntent { + /** + * Constructs an instance with the specified intent ID. + * + * @param id intent ID + */ + public TestSubclassInstallableIntent(int id) { //FIXME + super(id); + } + + /** + * Constructor for serializer. + */ + protected TestSubclassInstallableIntent() { + super(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestSubclassIntent.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestSubclassIntent.java new file mode 100644 index 00000000..44c81189 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestSubclassIntent.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 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.intent; + +/** + * An intent used in the unit test. + */ +public class TestSubclassIntent extends TestIntent { + /** + * Constructs an instance with the specified intent ID. + * + * @param id intent ID + */ + public TestSubclassIntent(int id) { //FIXME + super(id); + } + + /** + * Constructor for serializer. + */ + protected TestSubclassIntent() { + super(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestTools.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestTools.java new file mode 100644 index 00000000..80ae180d --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestTools.java @@ -0,0 +1,141 @@ +/* + * Copyright 2014 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.intent; + +import static org.junit.Assert.fail; + +/** + * Set of test tools. + */ +public final class TestTools { + + // Disallow construction + private TestTools() { + } + + /** + * Utility method to pause the current thread for the specified number of + * milliseconds. + * + * @param ms number of milliseconds to pause + */ + public static void delay(int ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + fail("unexpected interrupt"); + } + } + + /** + * Periodically runs the given runnable, which should contain a series of + * test assertions until all the assertions succeed, in which case it will + * return, or until the the time expires, in which case it will throw the + * first failed assertion error. + * + * @param start start time, in millis since start of epoch from which the + * duration will be measured + * @param delay initial delay (in milliseconds) before the first assertion + * attempt + * @param step delay (in milliseconds) between successive assertion + * attempts + * @param duration number of milliseconds beyond the given start time, + * after which the failed assertions will be propagated and allowed + * to fail the test + * @param assertions runnable housing the test assertions + */ + public static void assertAfter(long start, int delay, int step, + int duration, Runnable assertions) { + delay(delay); + while (true) { + try { + assertions.run(); + break; + } catch (AssertionError e) { + if (System.currentTimeMillis() - start > duration) { + throw e; + } + } + delay(step); + } + } + + /** + * Periodically runs the given runnable, which should contain a series of + * test assertions until all the assertions succeed, in which case it will + * return, or until the the time expires, in which case it will throw the + * first failed assertion error. + *

+ * The start of the period is the current time. + * + * @param delay initial delay (in milliseconds) before the first assertion + * attempt + * @param step delay (in milliseconds) between successive assertion + * attempts + * @param duration number of milliseconds beyond the current time time, + * after which the failed assertions will be propagated and allowed + * to fail the test + * @param assertions runnable housing the test assertions + */ + public static void assertAfter(int delay, int step, int duration, + Runnable assertions) { + assertAfter(System.currentTimeMillis(), delay, step, duration, + assertions); + } + + /** + * Periodically runs the given runnable, which should contain a series of + * test assertions until all the assertions succeed, in which case it will + * return, or until the the time expires, in which case it will throw the + * first failed assertion error. + *

+ * The start of the period is the current time and the first assertion + * attempt is delayed by the value of {@code step} parameter. + * + * @param step delay (in milliseconds) between successive assertion + * attempts + * @param duration number of milliseconds beyond the current time time, + * after which the failed assertions will be propagated and allowed + * to fail the test + * @param assertions runnable housing the test assertions + */ + public static void assertAfter(int step, int duration, + Runnable assertions) { + assertAfter(step, step, duration, assertions); + } + + /** + * Periodically runs the given runnable, which should contain a series of + * test assertions until all the assertions succeed, in which case it will + * return, or until the the time expires, in which case it will throw the + * first failed assertion error. + *

+ * The start of the period is the current time and each successive + * assertion attempt is delayed by at least 10 milliseconds unless the + * {@code duration} is less than that, in which case the one and only + * assertion is made after that delay. + * + * @param duration number of milliseconds beyond the current time, + * after which the failed assertions will be propagated and allowed + * to fail the test + * @param assertions runnable housing the test assertions + */ + public static void assertAfter(int duration, Runnable assertions) { + int step = Math.min(duration, Math.max(10, duration / 10)); + assertAfter(step, duration, assertions); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestableIntentService.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestableIntentService.java new file mode 100644 index 00000000..792c0ff8 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TestableIntentService.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 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.intent; + +import java.util.List; + +/** + * Abstraction of an extensible intent service enabled for unit tests. + */ +public interface TestableIntentService extends IntentService, IntentExtensionService { + + List getExceptions(); + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TwoWayP2PIntentTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TwoWayP2PIntentTest.java new file mode 100644 index 00000000..0986216a --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/TwoWayP2PIntentTest.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.intent; + +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.net.NetTestTools.APP_ID; +import static org.onosproject.net.NetTestTools.connectPoint; +/** + * Unit tests for the TwoWayP2PIntent class. + */ +public class TwoWayP2PIntentTest extends AbstractIntentTest { + + TrafficSelector selector; + TrafficTreatment treatment; + + TwoWayP2PIntent intent1; + TwoWayP2PIntent intent2; + + static final int PRIORITY = 12; + + @Before + public void twoWatP2PIntentTestSetUp() { + selector = new IntentTestsMocks.MockSelector(); + treatment = new IntentTestsMocks.MockTreatment(); + + intent1 = TwoWayP2PIntent.builder() + .appId(APP_ID) + .priority(PRIORITY) + .selector(selector) + .treatment(treatment) + .one(connectPoint("one", 1)) + .two(connectPoint("two", 2)) + .build(); + + intent2 = TwoWayP2PIntent.builder() + .appId(APP_ID) + .priority(PRIORITY) + .selector(selector) + .treatment(treatment) + .one(connectPoint("two", 2)) + .two(connectPoint("three", 2)) + .build(); + } + + /** + * Checks that the TwoWayP2PIntent class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(TwoWayP2PIntent.class); + } + + /** + * Checks the operation of equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(intent1) + .addEqualityGroup(intent2) + .testEquals(); + } + + /** + * Checks that the optical path ntent objects are created correctly. + */ + @Test + public void testContents() { + assertThat(intent1.appId(), equalTo(APP_ID)); + assertThat(intent1.one(), Matchers.equalTo(connectPoint("one", 1))); + assertThat(intent1.two(), Matchers.equalTo(connectPoint("two", 2))); + assertThat(intent1.priority(), is(PRIORITY)); + assertThat(intent1.selector(), is(selector)); + assertThat(intent1.treatment(), is(treatment)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/AnnotationConstraintTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/AnnotationConstraintTest.java new file mode 100644 index 00000000..b87dc12b --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/AnnotationConstraintTest.java @@ -0,0 +1,97 @@ +/* + * Copyright 2014 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.intent.constraint; + +import com.google.common.testing.EqualsTester; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.DefaultLink; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.PortNumber; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.net.resource.link.LinkResourceService; + +import static org.easymock.EasyMock.createMock; +import static org.hamcrest.Matchers.closeTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.lessThan; +import static org.junit.Assert.assertThat; +import static org.onosproject.net.DefaultLinkTest.cp; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.Link.Type.DIRECT; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Test for link annotated value threshold. + */ +public class AnnotationConstraintTest { + + private static final ProviderId PID = new ProviderId("of", "foo"); + private static final DeviceId DID1 = deviceId("of:1"); + private static final DeviceId DID2 = deviceId("of:2"); + private static final PortNumber PID1 = portNumber(1); + private static final PortNumber PID2 = portNumber(2); + private static final String KEY = "distance"; + private static final double VALUE = 100; + + private AnnotationConstraint sut; + private Link link; + private LinkResourceService linkResourceService; + + @Before + public void setUp() { + linkResourceService = createMock(LinkResourceService.class); + + DefaultAnnotations annotations = DefaultAnnotations.builder().set(KEY, String.valueOf(VALUE)).build(); + + link = new DefaultLink(PID, cp(DID1, PID1), cp(DID2, PID2), DIRECT, annotations); + } + + /** + * Tests the specified annotated value is less than the threshold. + */ + @Test + public void testLessThanThreshold() { + double value = 120; + sut = new AnnotationConstraint(KEY, value); + + assertThat(sut.isValid(link, linkResourceService), is(true)); + assertThat(sut.cost(link, linkResourceService), is(closeTo(VALUE, 1.0e-6))); + } + + /** + * Tests the specified annotated value is more than the threshold. + */ + @Test + public void testMoreThanThreshold() { + double value = 80; + sut = new AnnotationConstraint(KEY, value); + + assertThat(sut.isValid(link, linkResourceService), is(false)); + assertThat(sut.cost(link, linkResourceService), is(lessThan(0.0))); + } + + @Test + public void testEquality() { + new EqualsTester() + .addEqualityGroup(new AnnotationConstraint(KEY, 100), new AnnotationConstraint(KEY, 100)) + .addEqualityGroup(new AnnotationConstraint(KEY, 120)) + .addEqualityGroup(new AnnotationConstraint("latency", 100)) + .testEquals(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/ConstraintObjectsTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/ConstraintObjectsTest.java new file mode 100644 index 00000000..743fc252 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/ConstraintObjectsTest.java @@ -0,0 +1,135 @@ +/* + * Copyright 2014-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.intent.constraint; + +import org.junit.Test; +import org.onlab.util.Bandwidth; +import org.onosproject.net.Link; +import org.onosproject.net.resource.link.BandwidthResource; +import org.onosproject.net.resource.link.LambdaResource; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; + +/** + * Unit tests for Constraint objects. + */ +public class ConstraintObjectsTest { + + // Bandwidth Constraint + + private final Bandwidth bandwidth1 = Bandwidth.bps(100.0); + private final Bandwidth sameAsBandwidth1 = Bandwidth.bps(100.0); + private final Bandwidth bandwidth2 = Bandwidth.bps(200.0); + + final BandwidthConstraint bandwidthConstraint1 = + new BandwidthConstraint(new BandwidthResource(bandwidth1)); + final BandwidthConstraint bandwidthConstraintSameAs1 = + new BandwidthConstraint(new BandwidthResource(sameAsBandwidth1)); + final BandwidthConstraint bandwidthConstraint2 = + new BandwidthConstraint(new BandwidthResource(bandwidth2)); + + /** + * Checks that the objects were created properly. + */ + @Test + public void testBandwidthConstraintCreation() { + assertThat(bandwidthConstraint1.bandwidth().toDouble(), is(equalTo(100.0))); + assertThat(bandwidthConstraintSameAs1.bandwidth().toDouble(), is(equalTo(100.0))); + assertThat(bandwidthConstraint2.bandwidth().toDouble(), is(equalTo(200.0))); + } + + /** + * Checks the correctness of the equals() method. + */ + @Test + public void testBandwidthConstraintEquals() { + new EqualsTester() + .addEqualityGroup(bandwidthConstraint1, bandwidthConstraintSameAs1) + .addEqualityGroup(bandwidthConstraint2) + .testEquals(); + } + + // Lambda Constraint + + final LambdaConstraint lambdaConstraint1 = + new LambdaConstraint(LambdaResource.valueOf(100)); + final LambdaConstraint lambdaConstraintSameAs1 = + new LambdaConstraint(LambdaResource.valueOf(100)); + final LambdaConstraint lambdaConstraint2 = + new LambdaConstraint(LambdaResource.valueOf(200)); + + /** + * Checks that the objects were created properly. + */ + @Test + public void testLambdaConstraintCreation() { + assertThat(lambdaConstraint1.lambda().toInt(), is(equalTo(100))); + assertThat(lambdaConstraintSameAs1.lambda().toInt(), is(equalTo(100))); + assertThat(lambdaConstraint2.lambda().toInt(), is(equalTo(200))); + } + + /** + * Checks the correctness of the equals() method. + */ + @Test + public void testLambdaConstraintEquals() { + new EqualsTester() + .addEqualityGroup(lambdaConstraint1, lambdaConstraintSameAs1) + .addEqualityGroup(lambdaConstraint2) + .testEquals(); + } + + // LinkType Constraint + + final LinkTypeConstraint linkTypeConstraint1 = + new LinkTypeConstraint(true, Link.Type.OPTICAL, Link.Type.TUNNEL); + final LinkTypeConstraint linkTypeConstraintSameAs1 = + new LinkTypeConstraint(true, Link.Type.OPTICAL, Link.Type.TUNNEL); + final LinkTypeConstraint linkTypeConstraint2 = + new LinkTypeConstraint(true, Link.Type.OPTICAL, Link.Type.DIRECT); + + /** + * Checks that the objects were created properly. + */ + @Test + public void testLinkTypeConstraintCreation() { + assertThat(linkTypeConstraint1.isInclusive(), is(true)); + assertThat(linkTypeConstraint1.types(), + contains(Link.Type.OPTICAL, Link.Type.TUNNEL)); + assertThat(linkTypeConstraintSameAs1.isInclusive(), is(true)); + assertThat(linkTypeConstraintSameAs1.types(), + contains(Link.Type.OPTICAL, Link.Type.TUNNEL)); + assertThat(linkTypeConstraint2.isInclusive(), is(true)); + assertThat(linkTypeConstraint2.types(), + contains(Link.Type.OPTICAL, Link.Type.DIRECT)); + } + + /** + * Checks the correctness of the equals() method. + */ + @Test + public void testLinkTypeConstraintEquals() { + new EqualsTester() + .addEqualityGroup(linkTypeConstraint1, linkTypeConstraintSameAs1) + .addEqualityGroup(linkTypeConstraint2) + .testEquals(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/LatencyConstraintTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/LatencyConstraintTest.java new file mode 100644 index 00000000..bab17495 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/LatencyConstraintTest.java @@ -0,0 +1,124 @@ +/* + * Copyright 2014 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.intent.constraint; + +import com.google.common.testing.EqualsTester; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.net.Annotations; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.DefaultLink; +import org.onosproject.net.DefaultPath; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.PortNumber; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.net.resource.link.LinkResourceService; + +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.Arrays; + +import static org.easymock.EasyMock.createMock; +import static org.hamcrest.Matchers.closeTo; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.onosproject.net.AnnotationKeys.LATENCY; +import static org.onosproject.net.DefaultLinkTest.cp; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.Link.Type.DIRECT; + +public class LatencyConstraintTest { + + private static final DeviceId DID1 = deviceId("of:1"); + private static final DeviceId DID2 = deviceId("of:2"); + private static final DeviceId DID3 = deviceId("of:3"); + private static final PortNumber PN1 = PortNumber.portNumber(1); + private static final PortNumber PN2 = PortNumber.portNumber(2); + private static final PortNumber PN3 = PortNumber.portNumber(3); + private static final PortNumber PN4 = PortNumber.portNumber(4); + private static final ProviderId PROVIDER_ID = new ProviderId("of", "foo"); + private static final String LATENCY1 = "3.0"; + private static final String LATENCY2 = "4.0"; + + private LatencyConstraint sut; + private LinkResourceService linkResourceService; + + private Path path; + private Link link1; + private Link link2; + + @Before + public void setUp() { + linkResourceService = createMock(LinkResourceService.class); + + Annotations annotations1 = DefaultAnnotations.builder().set(LATENCY, LATENCY1).build(); + Annotations annotations2 = DefaultAnnotations.builder().set(LATENCY, LATENCY2).build(); + + link1 = new DefaultLink(PROVIDER_ID, cp(DID1, PN1), cp(DID2, PN2), DIRECT, annotations1); + link2 = new DefaultLink(PROVIDER_ID, cp(DID2, PN3), cp(DID3, PN4), DIRECT, annotations2); + path = new DefaultPath(PROVIDER_ID, Arrays.asList(link1, link2), 10); + } + + /** + * Tests the path latency is less than the supplied constraint. + */ + @Test + public void testLessThanLatency() { + sut = new LatencyConstraint(Duration.of(10, ChronoUnit.MICROS)); + + assertThat(sut.validate(path, linkResourceService), is(true)); + } + + /** + * Tests the path latency is more than the supplied constraint. + */ + @Test + public void testMoreThanLatency() { + sut = new LatencyConstraint(Duration.of(3, ChronoUnit.MICROS)); + + assertThat(sut.validate(path, linkResourceService), is(false)); + } + + /** + * Tests the link latency is equal to "latency" annotated value. + */ + @Test + public void testCost() { + sut = new LatencyConstraint(Duration.of(10, ChronoUnit.MICROS)); + + assertThat(sut.cost(link1, linkResourceService), is(closeTo(Double.parseDouble(LATENCY1), 1.0e-6))); + assertThat(sut.cost(link2, linkResourceService), is(closeTo(Double.parseDouble(LATENCY2), 1.0e-6))); + } + + /** + * Tests equality of the instances. + */ + @Test + public void testEquality() { + LatencyConstraint c1 = new LatencyConstraint(Duration.of(1, ChronoUnit.SECONDS)); + LatencyConstraint c2 = new LatencyConstraint(Duration.of(1000, ChronoUnit.MILLIS)); + + LatencyConstraint c3 = new LatencyConstraint(Duration.of(2, ChronoUnit.SECONDS)); + LatencyConstraint c4 = new LatencyConstraint(Duration.of(2000, ChronoUnit.MILLIS)); + + new EqualsTester() + .addEqualityGroup(c1, c2) + .addEqualityGroup(c3, c4) + .testEquals(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/ObstacleConstraintTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/ObstacleConstraintTest.java new file mode 100644 index 00000000..f02787f3 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/ObstacleConstraintTest.java @@ -0,0 +1,102 @@ +/* + * Copyright 2014 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.intent.constraint; + +/** + * Test for constraint of intermediate nodes not passed. + */ +import com.google.common.testing.EqualsTester; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.net.DefaultLink; +import org.onosproject.net.DefaultPath; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Path; +import org.onosproject.net.PortNumber; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.net.resource.link.LinkResourceService; + +import java.util.Arrays; + +import static org.easymock.EasyMock.createMock; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.*; +import static org.onosproject.net.DefaultLinkTest.cp; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.Link.Type.DIRECT; + +public class ObstacleConstraintTest { + + private static final DeviceId DID1 = deviceId("of:1"); + private static final DeviceId DID2 = deviceId("of:2"); + private static final DeviceId DID3 = deviceId("of:3"); + private static final DeviceId DID4 = deviceId("of:4"); + private static final PortNumber PN1 = PortNumber.portNumber(1); + private static final PortNumber PN2 = PortNumber.portNumber(2); + private static final PortNumber PN3 = PortNumber.portNumber(3); + private static final PortNumber PN4 = PortNumber.portNumber(4); + private static final ProviderId PROVIDER_ID = new ProviderId("of", "foo"); + + private LinkResourceService linkResourceService; + + private Path path; + private DefaultLink link2; + private DefaultLink link1; + + private ObstacleConstraint sut; + + @Before + public void setUp() { + linkResourceService = createMock(LinkResourceService.class); + + link1 = new DefaultLink(PROVIDER_ID, cp(DID1, PN1), cp(DID2, PN2), DIRECT); + link2 = new DefaultLink(PROVIDER_ID, cp(DID2, PN3), cp(DID3, PN4), DIRECT); + path = new DefaultPath(PROVIDER_ID, Arrays.asList(link1, link2), 10); + } + + @Test + public void testEquality() { + ObstacleConstraint o1 = new ObstacleConstraint(DID1, DID2, DID3); + ObstacleConstraint o2 = new ObstacleConstraint(DID3, DID2, DID1); + ObstacleConstraint o3 = new ObstacleConstraint(DID1, DID2); + ObstacleConstraint o4 = new ObstacleConstraint(DID2, DID1); + + new EqualsTester() + .addEqualityGroup(o1, o2) + .addEqualityGroup(o3, o4) + .testEquals(); + } + + /** + * Tests the specified path avoids the specified obstacle. + */ + @Test + public void testPathNotThroughObstacles() { + sut = new ObstacleConstraint(DID4); + + assertThat(sut.validate(path, linkResourceService), is(true)); + } + + /** + * Test the specified path does not avoid the specified obstacle. + */ + @Test + public void testPathThroughObstacle() { + sut = new ObstacleConstraint(DID1); + + assertThat(sut.validate(path, linkResourceService), is(false)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/WaypointConstraintTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/WaypointConstraintTest.java new file mode 100644 index 00000000..f7e212a3 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/intent/constraint/WaypointConstraintTest.java @@ -0,0 +1,104 @@ +/* + * Copyright 2014 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.intent.constraint; + +import com.google.common.testing.EqualsTester; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.net.DefaultLink; +import org.onosproject.net.DefaultPath; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Path; +import org.onosproject.net.PortNumber; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.net.resource.link.LinkResourceService; + +import java.util.Arrays; + +import static org.easymock.EasyMock.createMock; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.onosproject.net.DefaultLinkTest.cp; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.Link.Type.DIRECT; + +/** + * Test for constraint of intermediate elements. + */ +public class WaypointConstraintTest { + + private static final DeviceId DID1 = deviceId("of:1"); + private static final DeviceId DID2 = deviceId("of:2"); + private static final DeviceId DID3 = deviceId("of:3"); + private static final DeviceId DID4 = deviceId("of:4"); + private static final PortNumber PN1 = PortNumber.portNumber(1); + private static final PortNumber PN2 = PortNumber.portNumber(2); + private static final PortNumber PN3 = PortNumber.portNumber(3); + private static final PortNumber PN4 = PortNumber.portNumber(4); + private static final ProviderId PROVIDER_ID = new ProviderId("of", "foo"); + + private WaypointConstraint sut; + private LinkResourceService linkResourceService; + + private Path path; + private DefaultLink link2; + private DefaultLink link1; + + @Before + public void setUp() { + linkResourceService = createMock(LinkResourceService.class); + + link1 = new DefaultLink(PROVIDER_ID, cp(DID1, PN1), cp(DID2, PN2), DIRECT); + link2 = new DefaultLink(PROVIDER_ID, cp(DID2, PN3), cp(DID3, PN4), DIRECT); + path = new DefaultPath(PROVIDER_ID, Arrays.asList(link1, link2), 10); + } + + /** + * Tests that all of the specified waypoints are included in the specified path in order. + */ + @Test + public void testSatisfyWaypoints() { + sut = new WaypointConstraint(DID1, DID2, DID3); + + assertThat(sut.validate(path, linkResourceService), is(true)); + } + + /** + * Tests that the specified path does not includes the specified waypoint. + */ + @Test + public void testNotSatisfyWaypoint() { + sut = new WaypointConstraint(DID4); + + assertThat(sut.validate(path, linkResourceService), is(false)); + } + + @Test + public void testEquality() { + Constraint c1 = new WaypointConstraint(DID1, DID2); + Constraint c2 = new WaypointConstraint(DID1, DID2); + + Constraint c3 = new WaypointConstraint(DID2); + Constraint c4 = new WaypointConstraint(DID3); + + new EqualsTester() + .addEqualityGroup(c1, c2) + .addEqualityGroup(c3) + .addEqualityGroup(c4) + .testEquals(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/link/DefaultLinkDescriptionTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/link/DefaultLinkDescriptionTest.java new file mode 100644 index 00000000..3b98c5ba --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/link/DefaultLinkDescriptionTest.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014 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.link; + +import org.junit.Test; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.net.DefaultLinkTest.cp; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.Link.Type.DIRECT; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Test of the default link description. + */ +public class DefaultLinkDescriptionTest { + + private static final DeviceId DID1 = deviceId("of:foo"); + private static final DeviceId DID2 = deviceId("of:bar"); + private static final PortNumber P1 = portNumber(1); + + @Test + public void basics() { + LinkDescription desc = new DefaultLinkDescription(cp(DID1, P1), cp(DID2, P1), DIRECT); + assertEquals("incorrect src", cp(DID1, P1), desc.src()); + assertEquals("incorrect dst", cp(DID2, P1), desc.dst()); + assertEquals("incorrect type", DIRECT, desc.type()); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/link/LinkEventTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/link/LinkEventTest.java new file mode 100644 index 00000000..307fa69a --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/link/LinkEventTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2014 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.link; + +import org.junit.Test; +import org.onosproject.event.AbstractEventTest; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultLink; +import org.onosproject.net.Link; +import org.onosproject.net.provider.ProviderId; + +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Tests of the device event. + */ +public class LinkEventTest extends AbstractEventTest { + + private Link createLink() { + return new DefaultLink(new ProviderId("of", "foo"), + new ConnectPoint(deviceId("of:foo"), portNumber(1)), + new ConnectPoint(deviceId("of:bar"), portNumber(2)), + Link.Type.INDIRECT); + } + + @Test + public void withTime() { + Link link = createLink(); + LinkEvent event = new LinkEvent(LinkEvent.Type.LINK_ADDED, link, 123L); + validateEvent(event, LinkEvent.Type.LINK_ADDED, link, 123L); + } + + @Test + public void withoutTime() { + Link link = createLink(); + long before = System.currentTimeMillis(); + LinkEvent event = new LinkEvent(LinkEvent.Type.LINK_ADDED, link); + long after = System.currentTimeMillis(); + validateEvent(event, LinkEvent.Type.LINK_ADDED, link, before, after); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/link/LinkServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/link/LinkServiceAdapter.java new file mode 100644 index 00000000..5cb84b31 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/link/LinkServiceAdapter.java @@ -0,0 +1,97 @@ +/* + * Copyright 2014 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.link; + +import java.util.Set; + +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Link.State; + +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; + +/** + * Test adapter for link service. + */ +public class LinkServiceAdapter implements LinkService { + @Override + public int getLinkCount() { + return 0; + } + + @Override + public Iterable getLinks() { + return null; + } + + @Override + public Iterable getActiveLinks() { + return FluentIterable.from(getLinks()) + .filter(new Predicate() { + + @Override + public boolean apply(Link input) { + return input.state() == State.ACTIVE; + } + }); + } + + @Override + public Set getDeviceLinks(DeviceId deviceId) { + return null; + } + + @Override + public Set getDeviceEgressLinks(DeviceId deviceId) { + return null; + } + + @Override + public Set getDeviceIngressLinks(DeviceId deviceId) { + return null; + } + + @Override + public Set getLinks(ConnectPoint connectPoint) { + return null; + } + + @Override + public Set getEgressLinks(ConnectPoint connectPoint) { + return null; + } + + @Override + public Set getIngressLinks(ConnectPoint connectPoint) { + return null; + } + + @Override + public Link getLink(ConnectPoint src, ConnectPoint dst) { + return null; + } + + @Override + public void addListener(LinkListener listener) { + } + + @Override + public void removeListener(LinkListener listener) { + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/meter/DefaultMeterTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/meter/DefaultMeterTest.java new file mode 100644 index 00000000..b39d2efb --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/meter/DefaultMeterTest.java @@ -0,0 +1,99 @@ +/* + * 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.testing.EqualsTester; +import org.junit.Before; +import org.junit.Test; + +import java.util.Collections; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.onosproject.net.NetTestTools.APP_ID; +import static org.onosproject.net.NetTestTools.did; + + +/** + * DefaultMeter Tests. + */ +public class DefaultMeterTest { + + private Meter m1; + private Meter sameAsm1; + private Meter m2; + + @Before + public void setup() { + + Band band = DefaultBand.builder() + .ofType(Band.Type.DROP) + .withRate(500) + .build(); + + m1 = DefaultMeter.builder() + .forDevice(did("1")) + .fromApp(APP_ID) + .withId(MeterId.meterId(1)) + .withUnit(Meter.Unit.KB_PER_SEC) + .withBands(Collections.singletonList(band)) + .build(); + + sameAsm1 = DefaultMeter.builder() + .forDevice(did("1")) + .fromApp(APP_ID) + .withId(MeterId.meterId(1)) + .withUnit(Meter.Unit.KB_PER_SEC) + .withBands(Collections.singletonList(band)) + .build(); + + m2 = DefaultMeter.builder() + .forDevice(did("2")) + .fromApp(APP_ID) + .withId(MeterId.meterId(2)) + .withUnit(Meter.Unit.KB_PER_SEC) + .withBands(Collections.singletonList(band)) + .build(); + + } + + @Test + public void testEquality() { + new EqualsTester() + .addEqualityGroup(m1, sameAsm1) + .addEqualityGroup(m2).testEquals(); + } + + @Test + public void testConstruction() { + DefaultMeter m = (DefaultMeter) m1; + + assertThat(m.deviceId(), is(did("1"))); + assertThat(m.appId(), is(APP_ID)); + assertThat(m.id(), is(MeterId.meterId(1))); + assertThat(m.isBurst(), is(false)); + + assertThat(m.life(), is(0L)); + assertThat(m.bytesSeen(), is(0L)); + assertThat(m.packetsSeen(), is(0L)); + assertThat(m.referenceCount(), is(0L)); + + } + + + + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/meter/MeterOperationTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/meter/MeterOperationTest.java new file mode 100644 index 00000000..ad53e3a3 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/meter/MeterOperationTest.java @@ -0,0 +1,128 @@ +/* + * 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.testing.EqualsTester; +import org.junit.Test; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.DeviceId; + +import java.util.Collection; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBaseClass; + +/** + * Unit tests for the MeterOperationTest object. + */ +public class MeterOperationTest { + + + + /** + * Checks that the MeterOperation class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutableBaseClass(MeterOperation.class); + } + + @Test + public void testEquality() { + final Meter m1 = new TestMeter(); + final Meter m2 = new TestMeter(); + final MeterOperation op1 = new MeterOperation(m1, + MeterOperation.Type.ADD); + final MeterOperation sameAsOp1 = new MeterOperation(m1, + MeterOperation.Type.ADD); + final MeterOperation op2 = new MeterOperation(m2, + MeterOperation.Type.ADD); + + new EqualsTester() + .addEqualityGroup(op1, sameAsOp1) + .addEqualityGroup(op2) + .testEquals(); + } + + @Test + public void testConstruction() { + final Meter m1 = new TestMeter(); + + final MeterOperation op = new MeterOperation(m1, MeterOperation.Type.ADD); + + assertThat(op.meter(), is(m1)); + } + + private static final class TestMeter implements Meter { + + @Override + public DeviceId deviceId() { + return null; + } + + @Override + public MeterId id() { + return null; + } + + @Override + public ApplicationId appId() { + return null; + } + + @Override + public Unit unit() { + return null; + } + + @Override + public boolean isBurst() { + return false; + } + + @Override + public Collection bands() { + return null; + } + + @Override + public MeterState state() { + return null; + } + + @Override + public long life() { + return 0; + } + + @Override + public long referenceCount() { + return 0; + } + + @Override + public long packetsSeen() { + return 0; + } + + @Override + public long bytesSeen() { + return 0; + } + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourceAllocationTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourceAllocationTest.java new file mode 100644 index 00000000..a84927a0 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourceAllocationTest.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.net.newresource; + +import com.google.common.testing.EqualsTester; +import org.junit.Test; +import org.onlab.packet.VlanId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.LinkKey; +import org.onosproject.net.PortNumber; +import org.onosproject.net.intent.IntentId; + +public class ResourceAllocationTest { + + private static final DeviceId D1 = DeviceId.deviceId("of:001"); + private static final DeviceId D2 = DeviceId.deviceId("of:002"); + private static final PortNumber P1 = PortNumber.portNumber(1); + private static final ConnectPoint CP1_1 = new ConnectPoint(D1, P1); + private static final ConnectPoint CP2_1 = new ConnectPoint(D2, P1); + private static final VlanId VLAN1 = VlanId.vlanId((short) 100); + private static final IntentId IID1 = IntentId.valueOf(30); + private static final LinkKey LK1 = LinkKey.linkKey(CP1_1, CP2_1); + private static final LinkKey LK2 = LinkKey.linkKey(CP2_1, CP1_1); + + @Test + public void testEquals() { + ResourceAllocation alloc1 = new ResourceAllocation(new ResourcePath(LK1, VLAN1), IID1); + ResourceAllocation sameAsAlloc1 = new ResourceAllocation(new ResourcePath(LK1, VLAN1), IID1); + ResourceAllocation alloc2 = new ResourceAllocation(new ResourcePath(LK2, VLAN1), IID1); + + new EqualsTester() + .addEqualityGroup(alloc1, sameAsAlloc1) + .addEqualityGroup(alloc2) + .testEquals(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourcePathTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourcePathTest.java new file mode 100644 index 00000000..4a8886a4 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/newresource/ResourcePathTest.java @@ -0,0 +1,82 @@ +/* + * 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.newresource; + +import com.google.common.testing.EqualsTester; +import org.junit.Test; +import org.onlab.packet.VlanId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.LinkKey; +import org.onosproject.net.PortNumber; + +import java.util.Optional; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +public class ResourcePathTest { + + private static final DeviceId D1 = DeviceId.deviceId("of:001"); + private static final DeviceId D2 = DeviceId.deviceId("of:002"); + private static final PortNumber P1 = PortNumber.portNumber(1); + private static final ConnectPoint CP1_1 = new ConnectPoint(D1, P1); + private static final ConnectPoint CP2_1 = new ConnectPoint(D2, P1); + private static final VlanId VLAN1 = VlanId.vlanId((short) 100); + + @Test + public void testEquals() { + ResourcePath resource1 = new ResourcePath(LinkKey.linkKey(CP1_1, CP2_1), VLAN1); + ResourcePath sameAsResource1 = new ResourcePath(LinkKey.linkKey(CP1_1, CP2_1), VLAN1); + ResourcePath resource2 = new ResourcePath(LinkKey.linkKey(CP2_1, CP1_1), VLAN1); + + new EqualsTester() + .addEqualityGroup(resource1, sameAsResource1) + .addEqualityGroup(resource2) + .testEquals(); + } + + @Test + public void testCreateWithZeroComponent() { + ResourcePath path = new ResourcePath(); + + assertThat(path, is(ResourcePath.ROOT)); + } + + @Test + public void testThereIsParent() { + ResourcePath path = new ResourcePath(LinkKey.linkKey(CP1_1, CP2_1), VLAN1); + ResourcePath parent = new ResourcePath(LinkKey.linkKey(CP1_1, CP2_1)); + + assertThat(path.parent(), is(Optional.of(parent))); + } + + @Test + public void testNoParent() { + ResourcePath path = new ResourcePath(LinkKey.linkKey(CP1_1, CP2_1)); + + assertThat(path.parent(), is(Optional.of(ResourcePath.ROOT))); + } + + @Test + public void testBase() { + LinkKey linkKey = LinkKey.linkKey(CP1_1, CP2_1); + ResourcePath path = new ResourcePath(linkKey); + + LinkKey child = (LinkKey) path.lastComponent(); + assertThat(child, is(linkKey)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultInboundPacketTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultInboundPacketTest.java new file mode 100644 index 00000000..eda68240 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultInboundPacketTest.java @@ -0,0 +1,81 @@ +/* + * Copyright 2014 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; + +import java.nio.ByteBuffer; + +import org.junit.Test; +import org.onlab.packet.Ethernet; +import org.onlab.packet.MacAddress; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.net.NetTestTools.connectPoint; + +/** + * Unit tests for the DefaultInboundPacket class. + */ +public class DefaultInboundPacketTest { + + final Ethernet eth = new Ethernet() + .setDestinationMACAddress(MacAddress.BROADCAST) + .setSourceMACAddress(MacAddress.BROADCAST); + final ByteBuffer byteBuffer = ByteBuffer.wrap(eth.serialize()); + final DefaultInboundPacket packet1 = + new DefaultInboundPacket(connectPoint("d1", 1), + eth, + byteBuffer); + final DefaultInboundPacket sameAsPacket1 = + new DefaultInboundPacket(connectPoint("d1", 1), + eth, + byteBuffer); + final DefaultInboundPacket packet2 = + new DefaultInboundPacket(connectPoint("d2", 1), + eth, + byteBuffer); + /** + * Checks that the DefaultInboundPacket class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(DefaultInboundPacket.class); + } + + /** + * Tests the equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(packet1, sameAsPacket1) + .addEqualityGroup(packet2) + .testEquals(); + } + + /** + * Tests the object creation through the constructor. + */ + @Test + public void testConstruction() { + assertThat(packet1.receivedFrom(), equalTo(connectPoint("d1", 1))); + assertThat(packet1.parsed(), equalTo(eth)); + assertThat(packet1.unparsed(), notNullValue()); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultOutboundPacketTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultOutboundPacketTest.java new file mode 100644 index 00000000..21f997d9 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultOutboundPacketTest.java @@ -0,0 +1,82 @@ +/* + * Copyright 2014 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; + +import java.nio.ByteBuffer; + +import org.junit.Test; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.intent.IntentTestsMocks; +import org.onlab.packet.Ethernet; +import org.onlab.packet.MacAddress; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.net.NetTestTools.did; + +/** + * Unit tests for the DefaultOutboundPacketTest class. + */ +public class DefaultOutboundPacketTest { + final Ethernet eth = new Ethernet() + .setDestinationMACAddress(MacAddress.BROADCAST) + .setSourceMACAddress(MacAddress.BROADCAST); + final ByteBuffer byteBuffer = ByteBuffer.wrap(eth.serialize()); + final TrafficTreatment treatment = new IntentTestsMocks.MockTreatment(); + final DefaultOutboundPacket packet1 = + new DefaultOutboundPacket(did("d1"), + treatment, + byteBuffer); + final DefaultOutboundPacket sameAsPacket1 = + new DefaultOutboundPacket(did("d1"), + treatment, + byteBuffer); + final DefaultOutboundPacket packet2 = + new DefaultOutboundPacket(did("d2"), + treatment, + byteBuffer); + /** + * Checks that the DefaultOutboundPacket class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(DefaultOutboundPacket.class); + } + + /** + * Tests the equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(packet1, sameAsPacket1) + .addEqualityGroup(packet2) + .testEquals(); + } + + /** + * Tests the object creation through the constructor. + */ + @Test + public void testConstruction() { + assertThat(packet1.sendThrough(), equalTo(did("d1"))); + assertThat(packet1.data(), equalTo(byteBuffer)); + assertThat(packet1.treatment(), equalTo(treatment)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultPacketContextTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultPacketContextTest.java new file mode 100644 index 00000000..ee7ae7e5 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/DefaultPacketContextTest.java @@ -0,0 +1,112 @@ +/* + * Copyright 2014 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; + +import java.nio.ByteBuffer; + +import org.junit.Test; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.intent.IntentTestsMocks; +import org.onlab.packet.Ethernet; +import org.onlab.packet.MacAddress; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBaseClass; +import static org.onosproject.net.NetTestTools.connectPoint; +import static org.onosproject.net.NetTestTools.did; + +/** + * Unit tests for the DefaultPacketContextTest. + */ +public class DefaultPacketContextTest { + final Ethernet eth = new Ethernet() + .setDestinationMACAddress(MacAddress.BROADCAST) + .setSourceMACAddress(MacAddress.BROADCAST); + final ByteBuffer byteBuffer = ByteBuffer.wrap(eth.serialize()); + final DefaultInboundPacket inPacket = + new DefaultInboundPacket(connectPoint("d1", 1), + eth, + byteBuffer); + final TrafficTreatment treatment = new IntentTestsMocks.MockTreatment(); + final DefaultOutboundPacket outPacket = + new DefaultOutboundPacket(did("d1"), + treatment, + byteBuffer); + + static class MockPacketContext extends DefaultPacketContext { + + protected MockPacketContext(long time, InboundPacket inPkt, + OutboundPacket outPkt, boolean block) { + super(time, inPkt, outPkt, block); + } + + @Override + public void send() { + + } + + @Override + public boolean block() { + return super.block(); + } + } + + final DefaultPacketContext context1 = + new MockPacketContext(123L, inPacket, outPacket, true); + final DefaultPacketContext sameAsContext1 = + new MockPacketContext(123L, inPacket, outPacket, true); + final DefaultPacketContext context2 = + new MockPacketContext(123123L, inPacket, outPacket, true); + + /** + * Checks that the DefaultOutboundPacket class is immutable but can be + * used as a base class. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutableBaseClass(DefaultPacketContext.class); + } + + /** + * Tests the equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + // No hashCode() or equals() defined, object comparison is used. + new EqualsTester() + .addEqualityGroup(context1) + .addEqualityGroup(sameAsContext1) + .addEqualityGroup(context2) + .testEquals(); + } + + /** + * Tests that objects are created properly. + */ + @Test + public void testConstruction() { + assertThat(context1.block(), is(true)); + assertThat(context1.inPacket(), is(inPacket)); + assertThat(context1.isHandled(), is(true)); + assertThat(context1.outPacket(), is(outPacket)); + assertThat(context1.time(), is(123L)); + assertThat(context1.treatmentBuilder(), is(notNullValue())); + } +} 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 new file mode 100644 index 00000000..afe936b7 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/packet/PacketServiceAdapter.java @@ -0,0 +1,44 @@ +/* + * 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; + +import org.onosproject.core.ApplicationId; +import org.onosproject.net.flow.TrafficSelector; + +/** + * Test adapter for packet service. + */ +public class PacketServiceAdapter implements PacketService { + @Override + public void addProcessor(PacketProcessor processor, int priority) { + } + + @Override + public void removeProcessor(PacketProcessor processor) { + } + + @Override + public void requestPackets(TrafficSelector selector, PacketPriority priority, ApplicationId appId) { + } + + @Override + public void cancelPackets(TrafficSelector selector, PacketPriority priority, ApplicationId appId) { + } + + @Override + public void emit(OutboundPacket packet) { + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/AbstractProviderRegistryTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/AbstractProviderRegistryTest.java new file mode 100644 index 00000000..f08d93bd --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/AbstractProviderRegistryTest.java @@ -0,0 +1,108 @@ +/* + * Copyright 2014 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.provider; + +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; + +/** + * Test of the base provider registry. + */ +public class AbstractProviderRegistryTest { + + private class TestProviderService extends AbstractProviderService { + protected TestProviderService(TestProvider provider) { + super(provider); + } + } + + private class TestProviderRegistry extends AbstractProviderRegistry { + @Override + protected TestProviderService createProviderService(TestProvider provider) { + return new TestProviderService(provider); + } + } + + @Test + public void basics() { + TestProviderRegistry registry = new TestProviderRegistry(); + assertEquals("incorrect provider count", 0, registry.getProviders().size()); + + ProviderId fooId = new ProviderId("of", "foo"); + TestProvider pFoo = new TestProvider(fooId); + TestProviderService psFoo = registry.register(pFoo); + assertEquals("incorrect provider count", 1, registry.getProviders().size()); + assertThat("provider not found", registry.getProviders().contains(fooId)); + assertEquals("incorrect provider", psFoo.provider(), pFoo); + + ProviderId barId = new ProviderId("snmp", "bar"); + TestProvider pBar = new TestProvider(barId); + TestProviderService psBar = registry.register(pBar); + assertEquals("incorrect provider count", 2, registry.getProviders().size()); + assertThat("provider not found", registry.getProviders().contains(barId)); + assertEquals("incorrect provider", psBar.provider(), pBar); + + psFoo.checkValidity(); + registry.unregister(pFoo); + psBar.checkValidity(); + assertEquals("incorrect provider count", 1, registry.getProviders().size()); + assertThat("provider not found", registry.getProviders().contains(barId)); + } + + @Test + public void ancillaryProviders() { + TestProviderRegistry registry = new TestProviderRegistry(); + TestProvider pFoo = new TestProvider(new ProviderId("of", "foo")); + TestProvider pBar = new TestProvider(new ProviderId("of", "bar", true)); + registry.register(pFoo); + registry.register(pBar); + assertEquals("incorrect provider count", 2, registry.getProviders().size()); + } + + @Test(expected = IllegalStateException.class) + public void duplicateRegistration() { + TestProviderRegistry registry = new TestProviderRegistry(); + TestProvider pFoo = new TestProvider(new ProviderId("of", "foo")); + registry.register(pFoo); + registry.register(pFoo); + } + + @Test(expected = IllegalStateException.class) + public void duplicateSchemeRegistration() { + TestProviderRegistry registry = new TestProviderRegistry(); + TestProvider pFoo = new TestProvider(new ProviderId("of", "foo")); + TestProvider pBar = new TestProvider(new ProviderId("of", "bar")); + registry.register(pFoo); + registry.register(pBar); + } + + @Test + public void voidUnregistration() { + TestProviderRegistry registry = new TestProviderRegistry(); + registry.unregister(new TestProvider(new ProviderId("of", "foo"))); + } + + @Test(expected = IllegalStateException.class) + public void unregistration() { + TestProviderRegistry registry = new TestProviderRegistry(); + TestProvider pFoo = new TestProvider(new ProviderId("of", "foo")); + TestProviderService psFoo = registry.register(pFoo); + registry.unregister(pFoo); + psFoo.checkValidity(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/AbstractProviderTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/AbstractProviderTest.java new file mode 100644 index 00000000..e9e06c76 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/AbstractProviderTest.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 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.provider; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Test of the base provider implementation. + */ +public class AbstractProviderTest { + + @Test + public void basics() { + ProviderId id = new ProviderId("of", "foo.bar"); + TestProvider provider = new TestProvider(id); + assertEquals("incorrect id", id, provider.id()); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/ProviderIdTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/ProviderIdTest.java new file mode 100644 index 00000000..7e973991 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/ProviderIdTest.java @@ -0,0 +1,35 @@ +/* + * Copyright 2014 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.provider; + +import com.google.common.testing.EqualsTester; +import org.junit.Test; + +/** + * Test of the provider identifier. + */ +public class ProviderIdTest { + + @Test + public void basics() { + new EqualsTester() + .addEqualityGroup(new ProviderId("of", "foo"), new ProviderId("of", "foo")) + .addEqualityGroup(new ProviderId("snmp", "foo"), new ProviderId("snmp", "foo")) + .addEqualityGroup(new ProviderId("of", "bar")) + .testEquals(); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/TestProvider.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/TestProvider.java new file mode 100644 index 00000000..2f521bbb --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/provider/TestProvider.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014 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.provider; + +/** + * Test provider fixture. + */ +public class TestProvider extends AbstractProvider { + + /** + * Creates a provider with the supplier identifier. + * + * @param id provider id + */ + protected TestProvider(ProviderId id) { + super(id); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/resource/MplsObjectsTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/resource/MplsObjectsTest.java new file mode 100644 index 00000000..56f7a477 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/resource/MplsObjectsTest.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.resource; + +import org.junit.Test; + +import com.google.common.testing.EqualsTester; +import org.onosproject.net.resource.link.MplsLabel; +import org.onosproject.net.resource.link.MplsLabelResourceAllocation; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +/** + * Unit tests for MPLS objects. + */ +public class MplsObjectsTest { + + MplsLabel label1 = MplsLabel.valueOf(1); + MplsLabel label2 = MplsLabel.valueOf(2); + MplsLabel sameAsLabel1 = MplsLabel.valueOf(1); + MplsLabel sameAsLabel2 = MplsLabel.valueOf(2); + MplsLabel label3 = MplsLabel.valueOf(3); + + /** + * Tests creation of MPLS label objects. + */ + @Test + public void checkLabelConstruction() { + assertThat(label1.label().toInt(), is(1)); + } + + /** + * Tests the operation of equals(), hashCode() and toString(). + */ + @Test + public void testLabelEqualsOperation() { + new EqualsTester() + .addEqualityGroup(label1, sameAsLabel1) + .addEqualityGroup(label2, sameAsLabel2) + .addEqualityGroup(label3) + .testEquals(); + } + + MplsLabelResourceAllocation labelAllocation1 = + new MplsLabelResourceAllocation(label1); + MplsLabelResourceAllocation sameAsLabelAllocation1 = + new MplsLabelResourceAllocation(label1); + MplsLabelResourceAllocation labelAllocation2 = + new MplsLabelResourceAllocation(label2); + MplsLabelResourceAllocation sameAsLabelAllocation2 = + new MplsLabelResourceAllocation(label2); + MplsLabelResourceAllocation labelAllocation3 = + new MplsLabelResourceAllocation(label3); + + /** + * Tests creation of MPLS label objects. + */ + @Test + public void checkLabelResourceAllocationConstruction() { + assertThat(labelAllocation1.mplsLabel().label().toInt(), is(1)); + assertThat(labelAllocation1.type(), is(ResourceType.MPLS_LABEL)); + } + + /** + * Tests the operation of equals(), hashCode() and toString(). + */ + @Test + public void testLabelResourceAllocationEqualsOperation() { + new EqualsTester() + .addEqualityGroup(labelAllocation1, sameAsLabelAllocation1) + .addEqualityGroup(labelAllocation2, sameAsLabelAllocation2) + .addEqualityGroup(labelAllocation3) + .testEquals(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/statistic/DefaultLoadTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/statistic/DefaultLoadTest.java new file mode 100644 index 00000000..6b3ef93d --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/statistic/DefaultLoadTest.java @@ -0,0 +1,92 @@ +/* + * 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.junit.Before; +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.core.IsNot.not; + +/** + * Unit tests for DefaultLoad class. + */ +public class DefaultLoadTest { + + @Before + public void reset() { + DefaultLoad.setPollInterval(10); + } + + /** + * Tests the default constructor. + */ + @Test + public void testDefaultConstructor() { + DefaultLoad load = new DefaultLoad(); + assertThat(load.isValid(), is(false)); + assertThat(load.latest(), is(-1L)); + assertThat(load.rate(), is(0L)); + assertThat(load.time(), is(not(0))); + } + + /** + * Tests the current-previous constructor. + */ + @Test + public void testCurrentPreviousConstructor() { + DefaultLoad load = new DefaultLoad(20, 10); + assertThat(load.isValid(), is(true)); + assertThat(load.latest(), is(20L)); + assertThat(load.rate(), is(1L)); + assertThat(load.time(), is(not(0))); + } + + /** + * Tests the current-previous-interval constructor. + */ + @Test + public void testCurrentPreviousIntervalConstructor() { + DefaultLoad load = new DefaultLoad(20, 10, 1); + assertThat(load.isValid(), is(true)); + assertThat(load.latest(), is(20L)); + assertThat(load.rate(), is(10L)); + assertThat(load.time(), is(not(0))); + } + + /** + * Tests the toString operation. + */ + @Test + public void testToString() { + DefaultLoad load = new DefaultLoad(20, 10); + + String s = load.toString(); + assertThat(s, containsString("Load{rate=1, latest=20}")); + } + + /** + * Tests setting the poll interval. + */ + @Test + public void testSettingPollInterval() { + DefaultLoad.setPollInterval(1); + DefaultLoad load = new DefaultLoad(40, 10); + assertThat(load.rate(), is(30L)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/statistic/StatisticServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/statistic/StatisticServiceAdapter.java new file mode 100644 index 00000000..cf8f36f8 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/statistic/StatisticServiceAdapter.java @@ -0,0 +1,61 @@ +/* + * 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.core.ApplicationId; +import org.onosproject.core.GroupId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.flow.FlowRule; + +import java.util.Optional; + +/** + * Test adapter for statistics service. + */ +public class StatisticServiceAdapter implements StatisticService { + @Override + public Load load(Link link) { + return null; + } + + @Override + public Load load(ConnectPoint connectPoint) { + return null; + } + + @Override + public Link max(Path path) { + return null; + } + + @Override + public Link min(Path path) { + return null; + } + + @Override + public FlowRule highestHitter(ConnectPoint connectPoint) { + return null; + } + + @Override + public Load load(Link link, ApplicationId appId, Optional groupId) { + return null; + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/ClusterIdTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/ClusterIdTest.java new file mode 100644 index 00000000..1eb6331f --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/ClusterIdTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014 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 com.google.common.testing.EqualsTester; +import org.junit.Test; + +import static org.junit.Assert.*; +import static org.onosproject.net.topology.ClusterId.clusterId; + +/** + * Test of the cluster ID. + */ +public class ClusterIdTest { + + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(clusterId(1), clusterId(1)) + .addEqualityGroup(clusterId(3), clusterId(3)).testEquals(); + } + + @Test + public void basics() { + assertEquals("incorrect index", 123, clusterId(123).index()); + } + +} 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 new file mode 100644 index 00000000..8b0f8f05 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultGraphDescriptionTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 2014 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 com.google.common.collect.ImmutableSet; + +import org.junit.Test; +import org.onosproject.net.DefaultDevice; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.net.Device.Type.SWITCH; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.topology.DefaultTopologyEdgeTest.*; + +public class DefaultGraphDescriptionTest { + + static final DefaultTopologyEdge E1 = new DefaultTopologyEdge(V1, V2, L1); + static final DefaultTopologyEdge E2 = new DefaultTopologyEdge(V1, V2, L1); + + private static final DeviceId D3 = deviceId("3"); + + static final Device DEV1 = new DefaultDevice(PID, D1, SWITCH, "", "", "", "", null); + static final Device DEV2 = new DefaultDevice(PID, D2, SWITCH, "", "", "", "", null); + static final Device DEV3 = new DefaultDevice(PID, D3, SWITCH, "", "", "", "", null); + + @Test + public void basics() { + DefaultGraphDescription desc = + new DefaultGraphDescription(4321L, ImmutableSet.of(DEV1, DEV2, DEV3), + ImmutableSet.of(L1, L2)); + assertEquals("incorrect time", 4321L, desc.timestamp()); + assertEquals("incorrect vertex count", 3, desc.vertexes().size()); + assertEquals("incorrect edge count", 2, desc.edges().size()); + } + + @Test + public void missingVertex() { + GraphDescription desc = new DefaultGraphDescription(4321L, + ImmutableSet.of(DEV1, DEV3), + ImmutableSet.of(L1, L2)); + assertEquals("incorrect time", 4321L, desc.timestamp()); + assertEquals("incorrect vertex count", 2, desc.vertexes().size()); + assertEquals("incorrect edge count", 0, desc.edges().size()); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultTopologyClusterTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultTopologyClusterTest.java new file mode 100644 index 00000000..06ed8fde --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultTopologyClusterTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014-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 com.google.common.testing.EqualsTester; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.topology.ClusterId.clusterId; + +/** + * Test of the default topology cluster implementation. + */ +public class DefaultTopologyClusterTest { + + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(cluster(3, 2, 1, "of:1"), cluster(3, 2, 1, "of:1")) + .addEqualityGroup(cluster(3, 2, 1, "of:2"), cluster(3, 2, 1, "of:2")) + .addEqualityGroup(cluster(0, 2, 1, "of:1"), cluster(0, 2, 1, "of:1")) + .addEqualityGroup(cluster(3, 3, 1, "of:1"), cluster(3, 3, 1, "of:1")) + .testEquals(); + } + + @Test + public void basics() { + TopologyCluster cluster = cluster(6, 5, 4, "of:111"); + assertEquals("incorrect id", clusterId(6), cluster.id()); + assertEquals("incorrect id", 5, cluster.deviceCount()); + assertEquals("incorrect id", 4, cluster.linkCount()); + assertEquals("incorrect id", deviceId("of:111"), cluster.root().deviceId()); + + } + + private TopologyCluster cluster(int id, int dc, int lc, String root) { + return new DefaultTopologyCluster(clusterId(id), dc, lc, + new DefaultTopologyVertex(deviceId(root))); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultTopologyEdgeTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultTopologyEdgeTest.java new file mode 100644 index 00000000..830e9b9f --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultTopologyEdgeTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2014 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 com.google.common.testing.EqualsTester; +import org.junit.Test; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultLink; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.PortNumber; +import org.onosproject.net.provider.ProviderId; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Tests of the topology graph edge. + */ +public class DefaultTopologyEdgeTest { + + static final DeviceId D1 = deviceId("1"); + static final DeviceId D2 = deviceId("2"); + static final PortNumber P1 = portNumber(1); + static final PortNumber P2 = portNumber(2); + + static final ConnectPoint CP1 = new ConnectPoint(D1, P1); + static final ConnectPoint CP2 = new ConnectPoint(D2, P1); + static final ConnectPoint CP3 = new ConnectPoint(D2, P1); + static final ConnectPoint CP4 = new ConnectPoint(D1, P2); + + static final DefaultTopologyVertex V1 = new DefaultTopologyVertex(D1); + static final DefaultTopologyVertex V2 = new DefaultTopologyVertex(D2); + + static final ProviderId PID = new ProviderId("foo", "bar"); + + /** D1:P1 -> D2:P1. */ + static final Link L1 = new DefaultLink(PID, CP1, CP2, Link.Type.INDIRECT); + /** D2:P1 -> D1:P2. */ + static final Link L2 = new DefaultLink(PID, CP3, CP4, Link.Type.INDIRECT); + + @Test + public void basics() { + DefaultTopologyEdge e = new DefaultTopologyEdge(V1, V2, L1); + assertEquals("incorrect src", V1, e.src()); + assertEquals("incorrect dst", V2, e.dst()); + assertEquals("incorrect link", L1, e.link()); + + new EqualsTester() + .addEqualityGroup(new DefaultTopologyEdge(V1, V2, L1), + new DefaultTopologyEdge(V1, V2, L1)) + .addEqualityGroup(new DefaultTopologyEdge(V2, V1, L2), + new DefaultTopologyEdge(V2, V1, L2)) + .testEquals(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultTopologyVertexTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultTopologyVertexTest.java new file mode 100644 index 00000000..aa01d261 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/DefaultTopologyVertexTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014 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 com.google.common.testing.EqualsTester; +import org.junit.Test; +import org.onosproject.net.DeviceId; + +import static org.junit.Assert.*; +import static org.onosproject.net.DeviceId.deviceId; + +/** + * Tests of the topology graph vertex. + */ +public class DefaultTopologyVertexTest { + + private static final DeviceId D1 = deviceId("1"); + private static final DeviceId D2 = deviceId("2"); + + @Test + public void basics() { + DefaultTopologyVertex v = new DefaultTopologyVertex(D1); + assertEquals("incorrect device id", D1, v.deviceId()); + + new EqualsTester() + .addEqualityGroup(new DefaultTopologyVertex(D1), + new DefaultTopologyVertex(D1)) + .addEqualityGroup(new DefaultTopologyVertex(D2), + new DefaultTopologyVertex(D2)).testEquals(); + } +} 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 new file mode 100644 index 00000000..07e67842 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/net/topology/TopologyServiceAdapter.java @@ -0,0 +1,92 @@ +/* + * Copyright 2014 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.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Path; + +import java.util.Set; + +/** + * Test adapter for topology service. + */ +public class TopologyServiceAdapter implements TopologyService { + @Override + public Topology currentTopology() { + return null; + } + + @Override + public boolean isLatest(Topology topology) { + return false; + } + + @Override + public TopologyGraph getGraph(Topology topology) { + return null; + } + + @Override + public Set getClusters(Topology topology) { + return null; + } + + @Override + public TopologyCluster getCluster(Topology topology, ClusterId clusterId) { + return null; + } + + @Override + public Set getClusterDevices(Topology topology, TopologyCluster cluster) { + return null; + } + + @Override + public Set getClusterLinks(Topology topology, TopologyCluster cluster) { + return null; + } + + @Override + public Set getPaths(Topology topology, DeviceId src, DeviceId dst) { + return null; + } + + @Override + public Set getPaths(Topology topology, DeviceId src, DeviceId dst, LinkWeight weight) { + return null; + } + + @Override + public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) { + return false; + } + + @Override + public boolean isBroadcastPoint(Topology topology, ConnectPoint connectPoint) { + return false; + } + + @Override + public void addListener(TopologyListener listener) { + } + + @Override + public void removeListener(TopologyListener listener) { + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/ClusterCommunicationServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/ClusterCommunicationServiceAdapter.java new file mode 100644 index 00000000..04f890c8 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/ClusterCommunicationServiceAdapter.java @@ -0,0 +1,88 @@ +/* + * 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.cluster.messaging; + +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.onosproject.cluster.NodeId; + +/** + * Testing adapter for the cluster communication service. + */ +public class ClusterCommunicationServiceAdapter + implements ClusterCommunicationService { + + @Override + public void addSubscriber(MessageSubject subject, + ClusterMessageHandler subscriber, + ExecutorService executor) { + } + + @Override + public void removeSubscriber(MessageSubject subject) {} + + @Override + public void broadcast(M message, MessageSubject subject, + Function encoder) { + } + + @Override + public void broadcastIncludeSelf(M message, + MessageSubject subject, Function encoder) { + } + + @Override + public CompletableFuture unicast(M message, MessageSubject subject, + Function encoder, NodeId toNodeId) { + return null; + } + + @Override + public void multicast(M message, MessageSubject subject, + Function encoder, Set nodes) { + } + + @Override + public CompletableFuture sendAndReceive(M message, + MessageSubject subject, Function encoder, + Function decoder, NodeId toNodeId) { + return null; + } + + @Override + public void addSubscriber(MessageSubject subject, + Function decoder, Function handler, + Function encoder, Executor executor) { + } + + @Override + public void addSubscriber(MessageSubject subject, + Function decoder, Function> handler, + Function encoder) { + } + + @Override + public void addSubscriber(MessageSubject subject, + Function decoder, Consumer handler, + Executor executor) { + + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/ClusterMessageTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/ClusterMessageTest.java new file mode 100644 index 00000000..22f841b4 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/ClusterMessageTest.java @@ -0,0 +1,82 @@ +/* + * 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.cluster.messaging; + +import org.junit.Test; +import org.onosproject.cluster.NodeId; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +/** + * Units tests for ClusterMessage class. + */ +public class ClusterMessageTest { + private final MessageSubject subject1 = new MessageSubject("Message 1"); + private final MessageSubject subject2 = new MessageSubject("Message 2"); + + private final byte[] payload1 = {0, 1, 2, 3, 4, 5}; + private final byte[] payload2 = {0, 1, 2, 3, 4, 5, 6}; + + private final NodeId nodeId = new NodeId("node"); + + private final ClusterMessage message1 = + new ClusterMessage(nodeId, subject1, payload1); + private final ClusterMessage sameAsMessage1 = + new ClusterMessage(nodeId, subject1, payload1); + private final ClusterMessage message2 = + new ClusterMessage(nodeId, subject1, payload2); + private final ClusterMessage message3 = + new ClusterMessage(nodeId, subject2, payload1); + + /** + * Checks the operation of equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(message1, sameAsMessage1) + .addEqualityGroup(message2) + .addEqualityGroup(message3) + .testEquals(); + } + + /** + * Checks the construction of a FlowId object. + */ + @Test + public void testConstruction() { + assertThat(message1.payload(), is(payload1)); + assertThat(message1.sender(), is(nodeId)); + assertThat(message1.subject(), is(subject1)); + + byte[] response = {2, 2, 2, 2, 2, 2, 2, 2}; + message1.respond(response); + assertThat(message1.response(), is(response)); + } + + /** + * Tests the toBytes and fromBytes methods. + */ + @Test + public void testByteMethods() { + byte[] fromBytes = message3.getBytes(); + ClusterMessage message = ClusterMessage.fromBytes(fromBytes); + assertThat(message, is(message3)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/EndpointTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/EndpointTest.java new file mode 100644 index 00000000..c88c711a --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/EndpointTest.java @@ -0,0 +1,68 @@ +/* + * 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.cluster.messaging; + + +import org.junit.Test; +import org.onlab.packet.IpAddress; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +/** + * Unit tests for the Endpoint class. + */ +public class EndpointTest { + IpAddress host1 = IpAddress.valueOf("1.2.3.4"); + IpAddress host2 = IpAddress.valueOf("1.2.3.5"); + + private final Endpoint endpoint1 = new Endpoint(host1, 1); + private final Endpoint sameAsEndpoint1 = new Endpoint(host1, 1); + private final Endpoint endpoint2 = new Endpoint(host2, 1); + private final Endpoint endpoint3 = new Endpoint(host1, 2); + + /** + * Checks that the MessageSubject class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(Endpoint.class); + } + + /** + * Checks the operation of equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(endpoint1, sameAsEndpoint1) + .addEqualityGroup(endpoint2) + .addEqualityGroup(endpoint3) + .testEquals(); + } + + /** + * Checks the construction of a MessageSubject object. + */ + @Test + public void testConstruction() { + assertThat(endpoint2.host(), is(host2)); + assertThat(endpoint2.port(), is(1)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/MessageSubjectTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/MessageSubjectTest.java new file mode 100644 index 00000000..498edd33 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/cluster/messaging/MessageSubjectTest.java @@ -0,0 +1,64 @@ +/* + * 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.cluster.messaging; + +import org.junit.Test; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; + +/** + * Unit tests for MessageSubject class. + */ +public class MessageSubjectTest { + private final MessageSubject subject1 = new MessageSubject("Message 1"); + private final MessageSubject sameAsSubject1 = new MessageSubject("Message 1"); + private final MessageSubject subject2 = new MessageSubject("Message 2"); + private final MessageSubject subject3 = new MessageSubject("Message 3"); + + /** + * Checks that the MessageSubject class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(MessageSubject.class); + } + + /** + * Checks the operation of equals(), hashCode() and toString() methods. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(subject1, sameAsSubject1) + .addEqualityGroup(subject2) + .addEqualityGroup(subject3) + .testEquals(); + } + + /** + * Checks the construction of a MessageSubject object. + */ + @Test + public void testConstruction() { + assertThat(subject3.value(), is("Message 3")); + MessageSubject serializerObject = new MessageSubject(); + assertThat(serializerObject.value(), is("")); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/AtomicValueEventTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/AtomicValueEventTest.java new file mode 100644 index 00000000..39481ca0 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/AtomicValueEventTest.java @@ -0,0 +1,71 @@ +/* + * 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 org.junit.Test; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.store.service.AtomicValueEvent.Type.UPDATE; + +/** + * Unit tests for the AtomicValueEvent class. + */ +public class AtomicValueEventTest { + + AtomicValueEvent event1 = + new AtomicValueEvent<>("map1", UPDATE, "e1"); + AtomicValueEvent event2 = + new AtomicValueEvent<>("map1", UPDATE, "e2"); + AtomicValueEvent sameAsEvent2 = + new AtomicValueEvent<>("map1", UPDATE, "e2"); + AtomicValueEvent event3 = + new AtomicValueEvent<>("map2", UPDATE, "e2"); + + /** + * Checks that the SetEvent class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(AtomicValueEvent.class); + } + + /** + * Checks the equals(), hashCode() and toString() operations. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(event1) + .addEqualityGroup(event2, sameAsEvent2) + .addEqualityGroup(event3) + .testEquals(); + } + + /** + * Checks that construction of the object is correct. + */ + @Test + public void testConstruction() { + assertThat(event1.type(), is(UPDATE)); + assertThat(event1.value(), is("e1")); + assertThat(event1.name(), is("map1")); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/ConsistentMapAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/ConsistentMapAdapter.java new file mode 100644 index 00000000..d0c1adf6 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/ConsistentMapAdapter.java @@ -0,0 +1,149 @@ +/* + * 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.Collection; +import java.util.Map; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * Testing adapter for the consistent map. + */ +public class ConsistentMapAdapter implements ConsistentMap { + @Override + public int size() { + return 0; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean containsKey(K key) { + return false; + } + + @Override + public boolean containsValue(V value) { + return false; + } + + @Override + public Versioned get(K key) { + return null; + } + + @Override + public Versioned computeIfAbsent(K key, Function mappingFunction) { + return null; + } + + @Override + public Versioned compute(K key, BiFunction remappingFunction) { + return null; + } + + @Override + public Versioned computeIfPresent(K key, BiFunction remappingFunction) { + return null; + } + + @Override + public Versioned computeIf(K key, Predicate condition, + BiFunction remappingFunction) { + return null; + } + + @Override + public Versioned put(K key, V value) { + return null; + } + + @Override + public Versioned putAndGet(K key, V value) { + return null; + } + + @Override + public Versioned remove(K key) { + return null; + } + + @Override + public void clear() { + + } + + @Override + public Set keySet() { + return null; + } + + @Override + public Collection> values() { + return null; + } + + @Override + public Set>> entrySet() { + return null; + } + + @Override + public Versioned putIfAbsent(K key, V value) { + return null; + } + + @Override + public boolean remove(K key, V value) { + return false; + } + + @Override + public boolean remove(K key, long version) { + return false; + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + return false; + } + + @Override + public boolean replace(K key, long oldVersion, V newValue) { + return false; + } + + @Override + public void addListener(MapEventListener listener) { + + } + + @Override + public void removeListener(MapEventListener listener) { + + } + + @Override + public Map asJavaMap() { + return null; + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/DatabaseUpdateTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/DatabaseUpdateTest.java new file mode 100644 index 00000000..b498c1c7 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/DatabaseUpdateTest.java @@ -0,0 +1,127 @@ +/* + * 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 com.google.common.testing.EqualsTester; +import junit.framework.TestCase; +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +/** + * Unit Tests for DatabseUpdate class. + */ + +public class DatabaseUpdateTest extends TestCase { + + private final DatabaseUpdate stats1 = DatabaseUpdate.newBuilder() + .withCurrentValue("1".getBytes()) + .withValue("2".getBytes()) + .withCurrentVersion(3) + .withKey("4") + .withMapName("5") + .withType(DatabaseUpdate.Type.PUT) + .build(); + + private final DatabaseUpdate stats2 = DatabaseUpdate.newBuilder() + .withCurrentValue("1".getBytes()) + .withValue("2".getBytes()) + .withCurrentVersion(3) + .withKey("4") + .withMapName("5") + .withType(DatabaseUpdate.Type.REMOVE) + .build(); + + private final DatabaseUpdate stats3 = DatabaseUpdate.newBuilder() + .withCurrentValue("1".getBytes()) + .withValue("2".getBytes()) + .withCurrentVersion(3) + .withKey("4") + .withMapName("5") + .withType(DatabaseUpdate.Type.REMOVE_IF_VALUE_MATCH) + .build(); + + private final DatabaseUpdate stats4 = DatabaseUpdate.newBuilder() + .withCurrentValue("1".getBytes()) + .withValue("2".getBytes()) + .withCurrentVersion(3) + .withKey("4") + .withMapName("5") + .withType(DatabaseUpdate.Type.REMOVE_IF_VERSION_MATCH) + .build(); + + private final DatabaseUpdate stats5 = DatabaseUpdate.newBuilder() + .withCurrentValue("1".getBytes()) + .withValue("2".getBytes()) + .withCurrentVersion(3) + .withKey("4") + .withMapName("5") + .withType(DatabaseUpdate.Type.PUT_IF_VALUE_MATCH) + .build(); + + private final DatabaseUpdate stats6 = DatabaseUpdate.newBuilder() + .withCurrentValue("1".getBytes()) + .withValue("2".getBytes()) + .withCurrentVersion(3) + .withKey("4") + .withMapName("5") + .withType(DatabaseUpdate.Type.PUT_IF_VERSION_MATCH) + .build(); + + /** + * Tests the constructor for the class. + */ + @Test + public void testConstruction() { + assertThat(stats1.currentValue(), is("1".getBytes())); + assertThat(stats1.value(), is("2".getBytes())); + assertThat(stats1.currentVersion(), is(3L)); + assertThat(stats1.key(), is("4")); + assertThat(stats1.mapName(), is("5")); + assertThat(stats1.type(), is(DatabaseUpdate.Type.PUT)); + } + + /** + * Tests the equals, hashCode and toString methods using Guava EqualsTester. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(stats1, stats1) + .addEqualityGroup(stats2) + .testEquals(); + + new EqualsTester() + .addEqualityGroup(stats3, stats3) + .addEqualityGroup(stats4) + .testEquals(); + + new EqualsTester() + .addEqualityGroup(stats5, stats5) + .addEqualityGroup(stats6) + .testEquals(); + } + + /** + * Tests if the toString method returns a consistent value for hashing. + */ + @Test + public void testToString() { + assertThat(stats1.toString(), is(stats1.toString())); + } + +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/EventuallyConsistentMapAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/EventuallyConsistentMapAdapter.java new file mode 100644 index 00000000..07f5fb4d --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/EventuallyConsistentMapAdapter.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.service; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.function.BiFunction; + +/** + * Testing adapter for EventuallyConsistentMap. + */ +public class EventuallyConsistentMapAdapter implements EventuallyConsistentMap { + @Override + public int size() { + return 0; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean containsKey(K key) { + return false; + } + + @Override + public boolean containsValue(V value) { + return false; + } + + @Override + public V get(K key) { + return null; + } + + @Override + public void put(K key, V value) { + + } + + @Override + public V remove(K key) { + return null; + } + + @Override + public void remove(K key, V value) { + + } + + @Override + public V compute(K key, BiFunction recomputeFunction) { + return null; + } + + @Override + public void putAll(Map m) { + + } + + @Override + public void clear() { + + } + + @Override + public Set keySet() { + return null; + } + + @Override + public Collection values() { + return null; + } + + @Override + public Set> entrySet() { + return null; + } + + @Override + public void addListener(EventuallyConsistentMapListener listener) { + + } + + @Override + public void removeListener(EventuallyConsistentMapListener listener) { + + } + + @Override + public void destroy() { + + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/EventuallyConsistentMapEventTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/EventuallyConsistentMapEventTest.java new file mode 100644 index 00000000..a4163cb6 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/EventuallyConsistentMapEventTest.java @@ -0,0 +1,82 @@ +/* + * 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 org.junit.Test; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.PUT; +import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.REMOVE; + +/** + * Unit tests for the EventuallyConsistentMapEvent class. + */ +public class EventuallyConsistentMapEventTest { + + EventuallyConsistentMapEvent event1 = + new EventuallyConsistentMapEvent<>("map1", PUT, "k1", "v1"); + EventuallyConsistentMapEvent event2 = + new EventuallyConsistentMapEvent<>("map1", REMOVE, "k1", "v1"); + EventuallyConsistentMapEvent sameAsEvent2 = + new EventuallyConsistentMapEvent<>("map1", REMOVE, "k1", "v1"); + EventuallyConsistentMapEvent event3 = + new EventuallyConsistentMapEvent<>("map1", PUT, "k2", "v1"); + EventuallyConsistentMapEvent event4 = + new EventuallyConsistentMapEvent<>("map1", PUT, "k1", "v2"); + EventuallyConsistentMapEvent event5 = + new EventuallyConsistentMapEvent<>("map2", REMOVE, "k1", "v2"); + EventuallyConsistentMapEvent event6 = + new EventuallyConsistentMapEvent<>("map3", REMOVE, "k1", "v2"); + + + /** + * Checks the equals(), hashCode() and toString() operations. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(event1) + .addEqualityGroup(event2, sameAsEvent2) + .addEqualityGroup(event3) + .addEqualityGroup(event4) + .addEqualityGroup(event5) + .addEqualityGroup(event6) + .testEquals(); + } + + /** + * Checks that the EventuallyConsistentMapEvent class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(EventuallyConsistentMapEvent.class); + } + + /** + * Checks that construction of the object is correct. + */ + @Test + public void testConstruction() { + assertThat(event1.type(), is(PUT)); + assertThat(event1.key(), is("k1")); + assertThat(event1.value(), is("v1")); + assertThat(event1.name(), is("map1")); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/MapEventTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/MapEventTest.java new file mode 100644 index 00000000..c241c0e0 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/MapEventTest.java @@ -0,0 +1,61 @@ +/* + * 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 com.google.common.testing.EqualsTester; +import junit.framework.TestCase; +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +/** + * MapEvent unit tests. + */ +public class MapEventTest extends TestCase { + + private final Versioned vStats = new Versioned<>(2, 1); + + private final MapEvent stats1 = new MapEvent<>("a", MapEvent.Type.INSERT, "1", vStats); + + private final MapEvent stats2 = new MapEvent<>("a", MapEvent.Type.REMOVE, "1", vStats); + + private final MapEvent stats3 = new MapEvent<>("a", MapEvent.Type.UPDATE, "1", vStats); + + /** + * Tests the creation of the MapEvent object. + */ + @Test + public void testConstruction() { + assertThat(stats1.name(), is("a")); + assertThat(stats1.type(), is(MapEvent.Type.INSERT)); + assertThat(stats1.key(), is("1")); + assertThat(stats1.value(), is(vStats)); + } + + /** + * Tests the equals, hashCode and toString methods using Guava EqualsTester. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(stats1, stats1) + .addEqualityGroup(stats2) + .addEqualityGroup(stats3) + .testEquals(); + } + +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/MultiValuedTimestampTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/MultiValuedTimestampTest.java new file mode 100644 index 00000000..5d991a26 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/MultiValuedTimestampTest.java @@ -0,0 +1,94 @@ +/* + * 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 com.google.common.testing.EqualsTester; +import junit.framework.TestCase; + +import org.junit.Assert; +import org.junit.Test; + +import java.lang.reflect.Constructor; +import java.util.Arrays; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; + +/** + * MultiValuedTimestamp unit tests. + */ +public class MultiValuedTimestampTest extends TestCase { + + private final MultiValuedTimestamp stats1 = new MultiValuedTimestamp<>(1, 3); + + private final MultiValuedTimestamp stats2 = new MultiValuedTimestamp<>(1, 2); + + + /** + * Tests the creation of the MapEvent object. + */ + @Test + public void testConstruction() { + assertThat(stats1.value1(), is(1)); + assertThat(stats1.value2(), is(3)); + } + + /** + * Tests the toCompare function. + */ + @Test + public void testToCompare() { + assertThat(stats1.compareTo(stats2), is(1)); + } + + /** + * Tests the equals, hashCode and toString methods using Guava EqualsTester. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(stats1, stats1) + .addEqualityGroup(stats2) + .testEquals(); + } + + /** + * Tests that the empty argument list constructor for serialization + * is present and creates a proper object. + */ + @Test + public void testSerializerConstructor() { + try { + Constructor[] constructors = MultiValuedTimestamp.class.getDeclaredConstructors(); + assertThat(constructors, notNullValue()); + Arrays.stream(constructors).filter(ctor -> + ctor.getParameterTypes().length == 0) + .forEach(noParamsCtor -> { + try { + noParamsCtor.setAccessible(true); + MultiValuedTimestamp stats = + (MultiValuedTimestamp) noParamsCtor.newInstance(); + assertThat(stats, notNullValue()); + } catch (Exception e) { + Assert.fail("Exception instantiating no parameters constructor"); + } + }); + } catch (Exception e) { + Assert.fail("Exception looking up constructors"); + } + } +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/SetEventTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/SetEventTest.java new file mode 100644 index 00000000..5cc89d85 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/SetEventTest.java @@ -0,0 +1,75 @@ +/* + * 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 org.junit.Test; + +import com.google.common.testing.EqualsTester; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onosproject.store.service.SetEvent.Type.ADD; +import static org.onosproject.store.service.SetEvent.Type.REMOVE; + +/** + * Unit tests for the SetEvent class. + */ +public class SetEventTest { + + SetEvent event1 = + new SetEvent<>("map1", ADD, "e1"); + SetEvent event2 = + new SetEvent<>("map1", REMOVE, "e1"); + SetEvent sameAsEvent2 = + new SetEvent<>("map1", REMOVE, "e1"); + SetEvent event3 = + new SetEvent<>("map1", ADD, "e2"); + SetEvent event4 = + new SetEvent<>("map1", REMOVE, "e2"); + + /** + * Checks that the SetEvent class is immutable. + */ + @Test + public void testImmutability() { + assertThatClassIsImmutable(EventuallyConsistentMapEvent.class); + } + + /** + * Checks the equals(), hashCode() and toString() operations. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(event1) + .addEqualityGroup(event2, sameAsEvent2) + .addEqualityGroup(event3) + .addEqualityGroup(event4) + .testEquals(); + } + + /** + * Checks that construction of the object is correct. + */ + @Test + public void testConstruction() { + assertThat(event1.type(), is(ADD)); + assertThat(event1.entry(), is("e1")); + assertThat(event1.name(), is("map1")); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/StorageServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/StorageServiceAdapter.java new file mode 100644 index 00000000..ec04e331 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/StorageServiceAdapter.java @@ -0,0 +1,56 @@ +/* + * 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; + +/** + * Adapter for the storage service. + */ +public class StorageServiceAdapter implements StorageService { + @Override + public EventuallyConsistentMapBuilder eventuallyConsistentMapBuilder() { + return null; + } + + @Override + public ConsistentMapBuilder consistentMapBuilder() { + return null; + } + + @Override + public DistributedSetBuilder setBuilder() { + return null; + } + + @Override + public DistributedQueueBuilder queueBuilder() { + return null; + } + + @Override + public AtomicCounterBuilder atomicCounterBuilder() { + return null; + } + + @Override + public AtomicValueBuilder atomicValueBuilder() { + return null; + } + + @Override + public TransactionContextBuilder transactionContextBuilder() { + 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 new file mode 100644 index 00000000..01209be2 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestAtomicCounter.java @@ -0,0 +1,85 @@ +/* + * 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.atomic.AtomicLong; + +/** + * Test implementation of atomic counter. + */ +public final class TestAtomicCounter implements AtomicCounter { + final AtomicLong value; + + private TestAtomicCounter() { + value = new AtomicLong(); + } + + @Override + public long incrementAndGet() { + return value.incrementAndGet(); + } + + @Override + public long getAndIncrement() { + return value.getAndIncrement(); + } + + @Override + public long getAndAdd(long delta) { + return value.getAndAdd(delta); + } + + @Override + public long addAndGet(long delta) { + return value.addAndGet(delta); + } + + @Override + public long get() { + return value.get(); + } + + public static AtomicCounterBuilder builder() { + return new Builder(); + } + + public static class Builder implements AtomicCounterBuilder { + @Override + public AtomicCounterBuilder withName(String name) { + return this; + } + + @Override + public AtomicCounterBuilder withPartitionsDisabled() { + return this; + } + + @Override + public AtomicCounterBuilder withMeteringDisabled() { + return this; + } + + @Override + public AsyncAtomicCounter buildAsyncCounter() { + throw new UnsupportedOperationException("Async Counter is not supported"); + } + + @Override + public AtomicCounter build() { + return new TestAtomicCounter(); + } + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestConsistentMap.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestConsistentMap.java new file mode 100644 index 00000000..0136a94c --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestConsistentMap.java @@ -0,0 +1,287 @@ +/* + * 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.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import org.onosproject.core.ApplicationId; +import static org.onosproject.store.service.MapEvent.Type; +import static org.onosproject.store.service.MapEvent.Type.*; + +/** + * Test implementation of the consistent map. + */ +public final class TestConsistentMap extends ConsistentMapAdapter { + + private final List> listeners; + private final HashMap map; + private final String mapName; + private final AtomicLong counter = new AtomicLong(0); + + private TestConsistentMap(String mapName) { + map = new HashMap<>(); + listeners = new LinkedList<>(); + this.mapName = mapName; + } + + private Versioned version(V v) { + return new Versioned<>(v, counter.incrementAndGet(), System.currentTimeMillis()); + } + + /** + * Notify all listeners of an event. + */ + private void notifyListeners(String mapName, Type type, + K key, Versioned value) { + MapEvent event = new MapEvent<>(mapName, type, key, value); + listeners.forEach( + listener -> listener.event(event) + ); + } + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public boolean containsKey(K key) { + return map.containsKey(key); + } + + @Override + public boolean containsValue(V value) { + return map.containsValue(value); + } + + @Override + public Versioned get(K key) { + V value = map.get(key); + if (value != null) { + return version(value); + } else { + return null; + } + } + + @Override + public Versioned computeIfAbsent(K key, Function mappingFunction) { + Versioned result = version(map.computeIfAbsent(key, mappingFunction)); + notifyListeners(mapName, INSERT, key, result); + return result; + } + + @Override + public Versioned compute(K key, BiFunction remappingFunction) { + return version(map.compute(key, remappingFunction)); + } + + @Override + public Versioned computeIfPresent(K key, BiFunction remappingFunction) { + return version(map.computeIfPresent(key, remappingFunction)); + } + + @Override + public Versioned computeIf(K key, Predicate condition, + BiFunction remappingFunction) { + return null; + } + + @Override + public Versioned put(K key, V value) { + Versioned result = version(value); + if (map.put(key, value) == null) { + notifyListeners(mapName, INSERT, key, result); + } else { + notifyListeners(mapName, UPDATE, key, result); + } + return result; + } + + @Override + public Versioned putAndGet(K key, V value) { + Versioned result = version(map.put(key, value)); + notifyListeners(mapName, UPDATE, key, result); + return result; + } + + @Override + public Versioned remove(K key) { + Versioned result = version(map.remove(key)); + notifyListeners(mapName, REMOVE, key, result); + return result; + } + + @Override + public void clear() { + map.clear(); + } + + @Override + public Set keySet() { + return map.keySet(); + } + + @Override + public Collection> values() { + return map + .values() + .stream() + .map(this::version) + .collect(Collectors.toList()); + } + + @Override + public Set>> entrySet() { + return super.entrySet(); + } + + @Override + public Versioned putIfAbsent(K key, V value) { + Versioned result = version(map.putIfAbsent(key, value)); + if (map.get(key).equals(value)) { + notifyListeners(mapName, INSERT, key, result); + } + return result; + } + + @Override + public boolean remove(K key, V value) { + boolean removed = map.remove(key, value); + if (removed) { + notifyListeners(mapName, REMOVE, key, null); + } + return removed; + } + + @Override + public boolean remove(K key, long version) { + boolean removed = map.remove(key, version); + if (removed) { + notifyListeners(mapName, REMOVE, key, null); + } + return removed; + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + boolean replaced = map.replace(key, oldValue, newValue); + if (replaced) { + notifyListeners(mapName, REMOVE, key, null); + } + return replaced; + } + + @Override + public boolean replace(K key, long oldVersion, V newValue) { + boolean replaced = map.replace(key, map.get(key), newValue); + if (replaced) { + notifyListeners(mapName, REMOVE, key, null); + } + return replaced; + } + + @Override + public void addListener(MapEventListener listener) { + listeners.add(listener); + } + + @Override + public void removeListener(MapEventListener listener) { + listeners.remove(listener); + } + + @Override + public Map asJavaMap() { + return map; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder implements ConsistentMapBuilder { + String mapName = "map"; + + @Override + public ConsistentMapBuilder withName(String mapName) { + this.mapName = mapName; + return this; + } + + @Override + public ConsistentMapBuilder withApplicationId(ApplicationId id) { + return this; + } + + @Override + public ConsistentMapBuilder withSerializer(Serializer serializer) { + return this; + } + + @Override + public ConsistentMapBuilder withPartitionsDisabled() { + return this; + } + + @Override + public ConsistentMapBuilder withUpdatesDisabled() { + return this; + } + + @Override + public ConsistentMapBuilder withPurgeOnUninstall() { + return this; + } + + @Override + public ConsistentMapBuilder withRelaxedReadConsistency() { + return this; + } + + @Override + public ConsistentMapBuilder withMeteringDisabled() { + return this; + } + + @Override + public ConsistentMap build() { + return new TestConsistentMap<>(mapName); + } + + @Override + public AsyncConsistentMap buildAsyncMap() { + return null; + } + + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestEventuallyConsistentMap.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestEventuallyConsistentMap.java new file mode 100644 index 00000000..4f612de2 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestEventuallyConsistentMap.java @@ -0,0 +1,238 @@ +/* + * 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.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.function.BiFunction; + +import org.onlab.util.KryoNamespace; +import org.onosproject.cluster.NodeId; +import org.onosproject.store.Timestamp; + +import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.*; + +/** + * Testing version of an Eventually Consistent Map. + */ + +public final class TestEventuallyConsistentMap extends EventuallyConsistentMapAdapter { + + private final HashMap map; + private final String mapName; + private final List> listeners; + private final BiFunction> peerUpdateFunction; + + private TestEventuallyConsistentMap(String mapName, + BiFunction> peerUpdateFunction) { + map = new HashMap<>(); + listeners = new LinkedList<>(); + this.mapName = mapName; + this.peerUpdateFunction = peerUpdateFunction; + } + + /** + * Notify all listeners of an event. + */ + private void notifyListeners(EventuallyConsistentMapEvent event) { + listeners.forEach( + listener -> listener.event(event) + ); + } + + @Override + public int size() { + return map.size(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public boolean containsKey(K key) { + return map.containsKey(key); + } + + @Override + public boolean containsValue(V value) { + return map.containsValue(value); + } + + @Override + public V get(K key) { + return map.get(key); + } + + @Override + public void put(K key, V value) { + map.put(key, value); + EventuallyConsistentMapEvent addEvent = + new EventuallyConsistentMapEvent<>(mapName, PUT, key, value); + notifyListeners(addEvent); + if (peerUpdateFunction != null) { + peerUpdateFunction.apply(key, value); + } + } + + @Override + public V remove(K key) { + V result = map.remove(key); + if (result != null) { + EventuallyConsistentMapEvent removeEvent = + new EventuallyConsistentMapEvent<>(mapName, REMOVE, + key, map.get(key)); + notifyListeners(removeEvent); + } + return result; + } + + @Override + public void remove(K key, V value) { + boolean removed = map.remove(key, value); + if (removed) { + EventuallyConsistentMapEvent removeEvent = + new EventuallyConsistentMapEvent<>(mapName, REMOVE, key, value); + notifyListeners(removeEvent); + } + } + + @Override + public V compute(K key, BiFunction recomputeFunction) { + return map.compute(key, recomputeFunction); + } + + @Override + public void putAll(Map m) { + map.putAll(m); + } + + @Override + public void clear() { + map.clear(); + } + + @Override + public Set keySet() { + return map.keySet(); + } + + @Override + public Collection values() { + return map.values(); + } + + @Override + public Set> entrySet() { + return map.entrySet(); + } + + public static Builder builder() { + return new Builder<>(); + } + + @Override + public void addListener(EventuallyConsistentMapListener listener) { + listeners.add(listener); + } + + @Override + public void removeListener(EventuallyConsistentMapListener listener) { + listeners.remove(listener); + } + + public static class Builder implements EventuallyConsistentMapBuilder { + private String name; + private BiFunction> peerUpdateFunction; + + @Override + public EventuallyConsistentMapBuilder withName(String name) { + this.name = name; + return this; + } + + @Override + public EventuallyConsistentMapBuilder withSerializer(KryoNamespace.Builder serializerBuilder) { + return this; + } + + @Override + public EventuallyConsistentMapBuilder + withTimestampProvider(BiFunction timestampProvider) { + return this; + } + + @Override + public EventuallyConsistentMapBuilder withEventExecutor(ExecutorService executor) { + return this; + } + + @Override + public EventuallyConsistentMapBuilder withCommunicationExecutor(ExecutorService executor) { + return this; + } + + @Override + public EventuallyConsistentMapBuilder withBackgroundExecutor(ScheduledExecutorService executor) { + return this; + } + + @Override + public EventuallyConsistentMapBuilder + withPeerUpdateFunction(BiFunction> peerUpdateFunction) { + this.peerUpdateFunction = peerUpdateFunction; + return this; + } + + @Override + public EventuallyConsistentMapBuilder withTombstonesDisabled() { + return this; + } + + @Override + public EventuallyConsistentMapBuilder withAntiEntropyPeriod(long period, TimeUnit unit) { + return this; + } + + @Override + public EventuallyConsistentMapBuilder withFasterConvergence() { + return this; + } + + @Override + public EventuallyConsistentMapBuilder withPersistence() { + return this; + } + + @Override + public EventuallyConsistentMap build() { + if (name == null) { + name = "test"; + } + return new TestEventuallyConsistentMap<>(name, peerUpdateFunction); + } + } + +} + diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestStorageService.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestStorageService.java new file mode 100644 index 00000000..9b52a305 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/TestStorageService.java @@ -0,0 +1,55 @@ +/* + * 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; + +public class TestStorageService extends StorageServiceAdapter { + + + @Override + public EventuallyConsistentMapBuilder eventuallyConsistentMapBuilder() { + return TestEventuallyConsistentMap.builder(); + } + + @Override + public ConsistentMapBuilder consistentMapBuilder() { + return TestConsistentMap.builder(); + } + + @Override + public DistributedSetBuilder setBuilder() { + throw new UnsupportedOperationException("setBuilder"); + } + + @Override + public DistributedQueueBuilder queueBuilder() { + throw new UnsupportedOperationException("queueBuilder"); + } + + @Override + public AtomicCounterBuilder atomicCounterBuilder() { + return TestAtomicCounter.builder(); + } + + @Override + public AtomicValueBuilder atomicValueBuilder() { + throw new UnsupportedOperationException("atomicValueBuilder"); + } + + @Override + public TransactionContextBuilder transactionContextBuilder() { + throw new UnsupportedOperationException("transactionContextBuilder"); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/VersionedTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/VersionedTest.java new file mode 100644 index 00000000..8a401db2 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/VersionedTest.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.store.service; + +import com.google.common.testing.EqualsTester; +import junit.framework.TestCase; +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +/** + * Versioned unit tests. + */ +public class VersionedTest extends TestCase { + + private final Versioned stats1 = new Versioned<>(1, 2, 3); + + private final Versioned stats2 = new Versioned<>(1, 2); + + /** + * Tests the creation of the MapEvent object. + */ + @Test + public void testConstruction() { + assertThat(stats1.value(), is(1)); + assertThat(stats1.version(), is(2L)); + assertThat(stats1.creationTime(), is(3L)); + } + + /** + * Maps an Integer to a String - Utility function to test the map function. + * @param a Actual Integer parameter. + * @return String Mapped valued. + */ + public static String transform(Integer a) { + return Integer.toString(a); + } + + /** + * Tests the map function. + */ + @Test + public void testMap() { + Versioned tempObj = stats1.map(VersionedTest::transform); + assertThat(tempObj.value(), is("1")); + } + + /** + * Tests the valueOrElse method. + */ + @Test + public void testOrElse() { + Versioned vv = new Versioned<>("foo", 1); + Versioned nullVV = null; + assertThat(Versioned.valueOrElse(vv, "bar"), is("foo")); + assertThat(Versioned.valueOrElse(nullVV, "bar"), is("bar")); + } + + /** + * Tests the equals, hashCode and toString methods using Guava EqualsTester. + */ + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup(stats1, stats1) + .addEqualityGroup(stats2) + .testEquals(); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/WallClockTimestampTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/WallClockTimestampTest.java new file mode 100644 index 00000000..97f5a39b --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/store/service/WallClockTimestampTest.java @@ -0,0 +1,66 @@ +/* + * 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 static org.junit.Assert.assertTrue; + +import java.nio.ByteBuffer; + +import org.junit.Test; +import org.onosproject.store.Timestamp; +import org.onlab.util.KryoNamespace; + +import com.google.common.testing.EqualsTester; + +/** + * Tests for {@link WallClockTimestamp}. + */ +public class WallClockTimestampTest { + + @Test + public final void testBasic() throws InterruptedException { + WallClockTimestamp ts1 = new WallClockTimestamp(); + Thread.sleep(50); + WallClockTimestamp ts2 = new WallClockTimestamp(); + long stamp = System.currentTimeMillis() + 10000; + WallClockTimestamp ts3 = new WallClockTimestamp(stamp); + + + assertTrue(ts1.compareTo(ts1) == 0); + assertTrue(ts2.compareTo(ts1) > 0); + assertTrue(ts1.compareTo(ts2) < 0); + assertTrue(ts3.unixTimestamp() == stamp); + } + + @Test + public final void testKryoSerializable() { + WallClockTimestamp ts1 = new WallClockTimestamp(); + WallClockTimestamp ts2 = new WallClockTimestamp(System.currentTimeMillis() + 10000); + final ByteBuffer buffer = ByteBuffer.allocate(1 * 1024 * 1024); + final KryoNamespace kryos = KryoNamespace.newBuilder() + .register(WallClockTimestamp.class) + .build(); + + kryos.serialize(ts1, buffer); + buffer.flip(); + Timestamp copy = kryos.deserialize(buffer); + + new EqualsTester() + .addEqualityGroup(ts1, copy) + .addEqualityGroup(ts2) + .testEquals(); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/UiExtensionServiceAdapter.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/UiExtensionServiceAdapter.java new file mode 100644 index 00000000..68d9264c --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/UiExtensionServiceAdapter.java @@ -0,0 +1,41 @@ +/* + * 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; + +import java.util.List; + +/** + * Adapter for testing against UI extension service. + */ +public class UiExtensionServiceAdapter implements UiExtensionService { + @Override + public void register(UiExtension extension) { + } + + @Override + public void unregister(UiExtension extension) { + } + + @Override + public List getExtensions() { + return null; + } + + @Override + public UiExtension getViewExtension(String viewId) { + return null; + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/UiExtensionTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/UiExtensionTest.java new file mode 100644 index 00000000..bd3d15f6 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/UiExtensionTest.java @@ -0,0 +1,140 @@ +/* + * 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; + +import com.google.common.collect.ImmutableList; +import org.junit.Test; + +import java.io.IOException; +import java.util.List; + +import static com.google.common.io.ByteStreams.toByteArray; +import static org.junit.Assert.*; +import static org.onosproject.ui.UiView.Category.OTHER; + +/** + * Tests the default user interface extension descriptor. + */ +public class UiExtensionTest { + + private static final String FOO_ID = "foo"; + private static final String FOO_LABEL = "Foo View"; + private static final String BAR_ID = "bar"; + private static final String BAR_LABEL = "Bar View"; + private static final String CUSTOM = "custom"; + + + private static final UiView FOO_VIEW = new UiView(OTHER, FOO_ID, FOO_LABEL); + private static final UiView BAR_VIEW = new UiView(OTHER, BAR_ID, BAR_LABEL); + private static final UiView HIDDEN_VIEW = new UiViewHidden(FOO_ID); + + private static final UiMessageHandlerFactory MH_FACTORY = () -> null; + private static final UiTopoOverlayFactory TO_FACTORY = () -> null; + + private final ClassLoader cl = getClass().getClassLoader(); + + private List viewList; + private UiExtension ext; + private String css; + private String js; + private UiView view; + + + + @Test + public void basics() throws IOException { + viewList = ImmutableList.of(FOO_VIEW); + ext = new UiExtension.Builder(cl, viewList).build(); + + css = new String(toByteArray(ext.css())); + assertTrue("incorrect css stream", css.contains("foo-css")); + js = new String(toByteArray(ext.js())); + assertTrue("incorrect js stream", js.contains("foo-js")); + + assertEquals("expected 1 view", 1, ext.views().size()); + view = ext.views().get(0); + assertEquals("wrong view category", OTHER, view.category()); + assertEquals("wrong view id", FOO_ID, view.id()); + assertEquals("wrong view label", FOO_LABEL, view.label()); + + assertNull("unexpected message handler factory", ext.messageHandlerFactory()); + assertNull("unexpected topo overlay factory", ext.topoOverlayFactory()); + } + + @Test + public void withPath() throws IOException { + viewList = ImmutableList.of(FOO_VIEW); + ext = new UiExtension.Builder(cl, viewList) + .resourcePath(CUSTOM) + .build(); + + css = new String(toByteArray(ext.css())); + assertTrue("incorrect css stream", css.contains("custom-css")); + js = new String(toByteArray(ext.js())); + assertTrue("incorrect js stream", js.contains("custom-js")); + + assertEquals("expected 1 view", 1, ext.views().size()); + view = ext.views().get(0); + assertEquals("wrong view category", OTHER, view.category()); + assertEquals("wrong view id", FOO_ID, view.id()); + assertEquals("wrong view label", FOO_LABEL, view.label()); + + assertNull("unexpected message handler factory", ext.messageHandlerFactory()); + assertNull("unexpected topo overlay factory", ext.topoOverlayFactory()); + } + + @Test + public void messageHandlerFactory() { + viewList = ImmutableList.of(FOO_VIEW); + ext = new UiExtension.Builder(cl, viewList) + .messageHandlerFactory(MH_FACTORY) + .build(); + + assertEquals("wrong message handler factory", MH_FACTORY, + ext.messageHandlerFactory()); + assertNull("unexpected topo overlay factory", ext.topoOverlayFactory()); + } + + @Test + public void topoOverlayFactory() { + viewList = ImmutableList.of(HIDDEN_VIEW); + ext = new UiExtension.Builder(cl, viewList) + .topoOverlayFactory(TO_FACTORY) + .build(); + + assertNull("unexpected message handler factory", ext.messageHandlerFactory()); + assertEquals("wrong topo overlay factory", TO_FACTORY, + ext.topoOverlayFactory()); + } + + @Test + public void twoViews() { + viewList = ImmutableList.of(FOO_VIEW, BAR_VIEW); + ext = new UiExtension.Builder(cl, viewList).build(); + + assertEquals("expected 2 views", 2, ext.views().size()); + + view = ext.views().get(0); + assertEquals("wrong view category", OTHER, view.category()); + assertEquals("wrong view id", FOO_ID, view.id()); + assertEquals("wrong view label", FOO_LABEL, view.label()); + + view = ext.views().get(1); + assertEquals("wrong view category", OTHER, view.category()); + assertEquals("wrong view id", BAR_ID, view.id()); + assertEquals("wrong view label", BAR_LABEL, view.label()); + } +} \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/TableModelTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/TableModelTest.java new file mode 100644 index 00000000..7524bcb3 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/TableModelTest.java @@ -0,0 +1,338 @@ +/* + * 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; + +import org.junit.Test; +import org.onosproject.ui.table.TableModel.SortDir; +import org.onosproject.ui.table.cell.DefaultCellFormatter; +import org.onosproject.ui.table.cell.HexFormatter; + +import static org.junit.Assert.*; + +/** + * Unit tests for {@link TableModel}. + */ +public class TableModelTest { + + private static final String UNEX_SORT = "unexpected sort: index "; + + private static final String FOO = "foo"; + private static final String BAR = "bar"; + private static final String ZOO = "zoo"; + + private enum StarWars { + LUKE_SKYWALKER, LEIA_ORGANA, HAN_SOLO, C3PO, R2D2, JABBA_THE_HUTT + } + + private static class ParenFormatter implements CellFormatter { + @Override + public String format(Object value) { + return "(" + value + ")"; + } + } + + private TableModel tm; + private TableModel.Row[] rows; + private TableModel.Row row; + private CellFormatter fmt; + + @Test(expected = NullPointerException.class) + public void guardAgainstNull() { + tm = new TableModel(null); + } + + @Test(expected = IllegalArgumentException.class) + public void guardAgainstEmpty() { + tm = new TableModel(); + } + + @Test(expected = IllegalArgumentException.class) + public void guardAgainstDuplicateCols() { + tm = new TableModel(FOO, BAR, FOO); + } + + @Test + public void basic() { + tm = new TableModel(FOO, BAR); + assertEquals("column count", 2, tm.columnCount()); + assertEquals("row count", 0, tm.rowCount()); + } + + @Test + public void defaultFormatter() { + tm = new TableModel(FOO); + fmt = tm.getFormatter(FOO); + assertTrue("Wrong formatter", fmt instanceof DefaultCellFormatter); + } + + @Test(expected = IllegalArgumentException.class) + public void formatterBadColumn() { + tm = new TableModel(FOO); + fmt = tm.getFormatter(BAR); + } + + @Test + public void altFormatter() { + tm = new TableModel(FOO, BAR); + tm.setFormatter(BAR, new ParenFormatter()); + + fmt = tm.getFormatter(FOO); + assertTrue("Wrong formatter", fmt instanceof DefaultCellFormatter); + assertEquals("Wrong result", "2", fmt.format(2)); + + fmt = tm.getFormatter(BAR); + assertTrue("Wrong formatter", fmt instanceof ParenFormatter); + assertEquals("Wrong result", "(2)", fmt.format(2)); + } + + @Test + public void emptyRow() { + tm = new TableModel(FOO, BAR); + tm.addRow(); + assertEquals("bad row count", 1, tm.rowCount()); + } + + @Test(expected = IllegalArgumentException.class) + public void rowBadColumn() { + tm = new TableModel(FOO, BAR); + tm.addRow().cell(ZOO, 2); + } + + @Test + public void simpleRow() { + tm = new TableModel(FOO, BAR); + tm.addRow().cell(FOO, 3).cell(BAR, true); + assertEquals("bad row count", 1, tm.rowCount()); + row = tm.getRows()[0]; + assertEquals("bad cell", 3, row.get(FOO)); + assertEquals("bad cell", true, row.get(BAR)); + } + + + private static final String ONE = "one"; + private static final String TWO = "two"; + private static final String THREE = "three"; + private static final String FOUR = "four"; + private static final String ELEVEN = "eleven"; + private static final String TWELVE = "twelve"; + private static final String TWENTY = "twenty"; + private static final String THIRTY = "thirty"; + + private static final String[] NAMES = { + FOUR, + THREE, + TWO, + ONE, + ELEVEN, + TWELVE, + THIRTY, + TWENTY, + }; + private static final String[] SORTED_NAMES = { + ELEVEN, + FOUR, + ONE, + THIRTY, + THREE, + TWELVE, + TWENTY, + TWO, + }; + + private static final int[] NUMBERS = { + 4, 3, 2, 1, 11, 12, 30, 20 + }; + + private static final int[] SORTED_NUMBERS = { + 1, 2, 3, 4, 11, 12, 20, 30 + }; + + private static final String[] SORTED_HEX = { + "0x1", "0x2", "0x3", "0x4", "0xb", "0xc", "0x14", "0x1e" + }; + + @Test + public void verifyTestData() { + // not a unit test per se, but will fail if we don't keep + // the three test arrays in sync + int nalen = NAMES.length; + int snlen = SORTED_NAMES.length; + int nulen = NUMBERS.length; + + if (nalen != snlen || nalen != nulen) { + fail("test data array size discrepancy"); + } + } + + private void initUnsortedTable() { + tm = new TableModel(FOO, BAR); + for (int i = 0; i < NAMES.length; i++) { + tm.addRow().cell(FOO, NAMES[i]).cell(BAR, NUMBERS[i]); + } + } + + @Test + public void tableStringSort() { + initUnsortedTable(); + + // sort by name + tm.sort(FOO, SortDir.ASC); + + // verify results + rows = tm.getRows(); + int nr = rows.length; + assertEquals("row count", NAMES.length, nr); + for (int i = 0; i < nr; i++) { + assertEquals(UNEX_SORT + i, SORTED_NAMES[i], rows[i].get(FOO)); + } + + // now the other way + tm.sort(FOO, SortDir.DESC); + + // verify results + rows = tm.getRows(); + nr = rows.length; + assertEquals("row count", NAMES.length, nr); + for (int i = 0; i < nr; i++) { + assertEquals(UNEX_SORT + i, + SORTED_NAMES[nr - 1 - i], rows[i].get(FOO)); + } + } + + @Test + public void tableNumberSort() { + initUnsortedTable(); + + // sort by number + tm.sort(BAR, SortDir.ASC); + + // verify results + rows = tm.getRows(); + int nr = rows.length; + assertEquals("row count", NUMBERS.length, nr); + for (int i = 0; i < nr; i++) { + assertEquals(UNEX_SORT + i, SORTED_NUMBERS[i], rows[i].get(BAR)); + } + + // now the other way + tm.sort(BAR, SortDir.DESC); + + // verify results + rows = tm.getRows(); + nr = rows.length; + assertEquals("row count", NUMBERS.length, nr); + for (int i = 0; i < nr; i++) { + assertEquals(UNEX_SORT + i, + SORTED_NUMBERS[nr - 1 - i], rows[i].get(BAR)); + } + } + + @Test + public void sortAndFormat() { + initUnsortedTable(); + + // set hex formatter + tm.setFormatter(BAR, HexFormatter.INSTANCE); + + // sort by number + tm.sort(BAR, SortDir.ASC); + + // verify results + rows = tm.getRows(); + int nr = rows.length; + assertEquals("row count", SORTED_HEX.length, nr); + for (int i = 0; i < nr; i++) { + assertEquals(UNEX_SORT + i, SORTED_HEX[i], rows[i].getAsString(BAR)); + } + } + + private static final String[][] SORTED_NAMES_AND_HEX = { + {ELEVEN, "0xb"}, + {FOUR, "0x4"}, + {ONE, "0x1"}, + {THIRTY, "0x1e"}, + {THREE, "0x3"}, + {TWELVE, "0xc"}, + {TWENTY, "0x14"}, + {TWO, "0x2"}, + }; + + @Test + public void sortAndFormatTwo() { + initUnsortedTable(); + tm.setFormatter(BAR, HexFormatter.INSTANCE); + tm.sort(FOO, SortDir.ASC); + rows = tm.getRows(); + int nr = rows.length; + for (int i = 0; i < nr; i++) { + String[] exp = SORTED_NAMES_AND_HEX[i]; + String[] act = rows[i].getAsFormattedStrings(); + assertArrayEquals(UNEX_SORT + i, exp, act); + } + } + + private static final String[] FBZ = {FOO, BAR, ZOO}; + + @Test + public void getColumnIds() { + tm = new TableModel(FOO, BAR, ZOO); + assertArrayEquals("col IDs", FBZ, tm.getColumnIds()); + } + + @Test + public void sortDirAsc() { + assertEquals("asc sort dir", SortDir.ASC, TableModel.sortDir("asc")); + } + + @Test + public void sortDirDesc() { + assertEquals("desc sort dir", SortDir.DESC, TableModel.sortDir("desc")); + } + + @Test + public void sortDirOther() { + assertEquals("other sort dir", SortDir.ASC, TableModel.sortDir("other")); + } + + @Test + public void sortDirNull() { + assertEquals("null sort dir", SortDir.ASC, TableModel.sortDir(null)); + } + + + @Test + public void enumSort() { + tm = new TableModel(FOO); + tm.addRow().cell(FOO, StarWars.HAN_SOLO); + tm.addRow().cell(FOO, StarWars.C3PO); + tm.addRow().cell(FOO, StarWars.JABBA_THE_HUTT); + tm.addRow().cell(FOO, StarWars.LEIA_ORGANA); + tm.addRow().cell(FOO, StarWars.R2D2); + tm.addRow().cell(FOO, StarWars.LUKE_SKYWALKER); + + tm.sort(FOO, SortDir.ASC); + + // verify expected results + StarWars[] ordered = StarWars.values(); + TableModel.Row[] rows = tm.getRows(); + assertEquals("wrong length?", ordered.length, rows.length); + int nr = rows.length; + for (int i = 0; i < nr; i++) { + assertEquals(UNEX_SORT + i, ordered[i], rows[i].get(FOO)); + } + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/TableUtilsTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/TableUtilsTest.java new file mode 100644 index 00000000..7c2f2d73 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/TableUtilsTest.java @@ -0,0 +1,45 @@ +/* + * 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; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.junit.Assert; +import org.junit.Test; + +/** + * Unit tests for {@link TableUtils}. + */ +public class TableUtilsTest { + + private static final String FOO = "foo"; + private static final String BAR = "bar"; + + private static final String ARRAY_AS_STRING = + "[{\"foo\":\"1\",\"bar\":\"2\"},{\"foo\":\"3\",\"bar\":\"4\"}]"; + + @Test + public void basic() { + TableModel tm = new TableModel(FOO, BAR); + tm.addRow().cell(FOO, 1).cell(BAR, 2); + tm.addRow().cell(FOO, 3).cell(BAR, 4); + + ArrayNode array = TableUtils.generateArrayNode(tm); + Assert.assertEquals("wrong results", ARRAY_AS_STRING, array.toString()); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/AbstractCellComparatorTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/AbstractCellComparatorTest.java new file mode 100644 index 00000000..0b9af23d --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/AbstractCellComparatorTest.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.ui.table.cell; + +import org.junit.Test; +import org.onosproject.ui.table.CellComparator; + +import static org.junit.Assert.assertTrue; + +/** + * Unit tests for {@link AbstractCellComparator}. + */ +public class AbstractCellComparatorTest { + + private static class Concrete extends AbstractCellComparator { + @Override + protected int nonNullCompare(Object o1, Object o2) { + return 42; + } + } + + private CellComparator cmp = new Concrete(); + + @Test + public void twoNullArgs() { + assertTrue("two nulls", cmp.compare(null, null) == 0); + } + + @Test + public void nullArgOne() { + assertTrue("null one", cmp.compare(null, 1) < 0); + } + + @Test + public void nullArgTwo() { + assertTrue("null two", cmp.compare(1, null) > 0); + } + + // mock output, but check that our method was invoked... + @Test + public void noNulls() { + assertTrue("no Nulls", cmp.compare(1, 2) == 42); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/AbstractCellFormatterTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/AbstractCellFormatterTest.java new file mode 100644 index 00000000..7a3c34bc --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/AbstractCellFormatterTest.java @@ -0,0 +1,52 @@ +/* + * 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 org.junit.Test; +import org.onosproject.ui.table.CellFormatter; + +import static org.junit.Assert.assertEquals; + +/** + * Unit tests for {@link AbstractCellFormatter}. + */ +public class AbstractCellFormatterTest { + + private static final String MOCK_OUTPUT = "Mock!!"; + + private static class Concrete extends AbstractCellFormatter { + @Override + protected String nonNullFormat(Object value) { + return MOCK_OUTPUT; + } + } + + private CellFormatter frm = new Concrete(); + + @Test + public void nullInput() { + assertEquals("wrong result", "", frm.format(null)); + } + + // mock output, but check that our method was invoked... + @Test + public void nonNullInput() { + assertEquals("what?", MOCK_OUTPUT, frm.format(1)); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/AppIdFormatterTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/AppIdFormatterTest.java new file mode 100644 index 00000000..e74fb47c --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/AppIdFormatterTest.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 org.junit.Test; +import org.onosproject.core.ApplicationId; +import org.onosproject.ui.table.CellFormatter; + +import static org.junit.Assert.assertEquals; + +/** + * Unit tests for {@link AppIdFormatter}. + */ +public class AppIdFormatterTest { + + private static final ApplicationId APP_ID = new ApplicationId() { + @Override + public short id() { + return 25; + } + + @Override + public String name() { + return "some app"; + } + }; + + private CellFormatter fmt = AppIdFormatter.INSTANCE; + + @Test + public void basic() { + assertEquals("wrong format", "25 : some app", fmt.format(APP_ID)); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/ConnectPointFormatterTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/ConnectPointFormatterTest.java new file mode 100644 index 00000000..65fd7843 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/ConnectPointFormatterTest.java @@ -0,0 +1,45 @@ +/* + * 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 org.junit.Test; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; +import org.onosproject.ui.table.CellFormatter; + +import static org.junit.Assert.assertEquals; + +/** + * Unit tests for {@link ConnectPointFormatter}. + */ +public class ConnectPointFormatterTest { + + private static final DeviceId DEVID = DeviceId.deviceId("foobar"); + private static final PortNumber PORT = PortNumber.portNumber(42); + + private static final ConnectPoint CP = new ConnectPoint(DEVID, PORT); + + private CellFormatter fmt = ConnectPointFormatter.INSTANCE; + + @Test + public void basic() { + assertEquals("wrong format", "foobar/42", fmt.format(CP)); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/DefaultCellComparatorTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/DefaultCellComparatorTest.java new file mode 100644 index 00000000..87c95288 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/DefaultCellComparatorTest.java @@ -0,0 +1,147 @@ +/* + * 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 org.junit.Test; +import org.onosproject.ui.table.CellComparator; + +import static org.junit.Assert.assertTrue; + +/** + * Unit tests for {@link DefaultCellComparator}. + */ +public class DefaultCellComparatorTest { + + private static final String SOME = "SoMeStRiNg"; + private static final String OTHER = "OtherSTRING"; + + private CellComparator cmp = DefaultCellComparator.INSTANCE; + + // default comparator should detect Comparable impls and use that + + @Test + public void sameString() { + assertTrue("same string", cmp.compare(SOME, SOME) == 0); + } + + @Test + public void someVsOther() { + assertTrue("some vs other", cmp.compare(SOME, OTHER) > 0); + } + + @Test + public void otherVsSome() { + assertTrue("other vs some", cmp.compare(OTHER, SOME) < 0); + } + + @Test + public void someVsNull() { + assertTrue("some vs null", cmp.compare(SOME, null) > 0); + } + + @Test + public void nullVsSome() { + assertTrue("null vs some", cmp.compare(null, SOME) < 0); + } + + @Test(expected = ClassCastException.class) + public void mismatch() { + cmp.compare(42, SOME); + } + + + @Test + public void strElevenTwo() { + assertTrue("str 11 vs 2", cmp.compare("11", "2") < 0); + } + + @Test + public void intElevenTwo() { + assertTrue("int 11 vs 2", cmp.compare(11, 2) > 0); + } + + + @Test + public void intSmallBig() { + assertTrue("int 2 vs 4", cmp.compare(2, 4) < 0); + } + + @Test + public void intBigSmall() { + assertTrue("int 4 vs 2", cmp.compare(4, 2) > 0); + } + + @Test + public void intEqual() { + assertTrue("int 4 vs 4", cmp.compare(4, 4) == 0); + } + + @Test + public void longSmallBig() { + assertTrue("long 2 vs 4", cmp.compare(2L, 4L) < 0); + } + + @Test + public void longBigSmall() { + assertTrue("long 4 vs 2", cmp.compare(4L, 2L) > 0); + } + + @Test + public void longEqual() { + assertTrue("long 4 vs 4", cmp.compare(4L, 4L) == 0); + } + + + private enum SmallStarWars { C3PO, R2D2, LUKE } + + @Test + public void swEpisodeI() { + assertTrue("c3po r2d2", + cmp.compare(SmallStarWars.C3PO, SmallStarWars.R2D2) < 0); + } + + @Test + public void swEpisodeII() { + assertTrue("r2d2 c3po", + cmp.compare(SmallStarWars.R2D2, SmallStarWars.C3PO) > 0); + } + + @Test + public void swEpisodeIII() { + assertTrue("luke c3po", + cmp.compare(SmallStarWars.LUKE, SmallStarWars.C3PO) > 0); + } + + @Test + public void swEpisodeIV() { + assertTrue("c3po luke", + cmp.compare(SmallStarWars.C3PO, SmallStarWars.LUKE) < 0); + } + + @Test + public void swEpisodeV() { + assertTrue("luke r2d2", + cmp.compare(SmallStarWars.LUKE, SmallStarWars.R2D2) > 0); + } + + @Test + public void swEpisodeVI() { + assertTrue("r2d2 luke", + cmp.compare(SmallStarWars.R2D2, SmallStarWars.LUKE) < 0); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/DefaultCellFormatterTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/DefaultCellFormatterTest.java new file mode 100644 index 00000000..6351a1f4 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/DefaultCellFormatterTest.java @@ -0,0 +1,71 @@ +/* + * 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 org.junit.Test; +import org.onosproject.ui.table.CellFormatter; + +import static org.junit.Assert.assertEquals; + +/** + * Unit tests for {@link DefaultCellFormatter}. + */ +public class DefaultCellFormatterTest { + + private static final String UNEX = "Unexpected result"; + private static final String SOME_STRING = "SoMeStRiNg"; + + private static class TestClass { + @Override + public String toString() { + return SOME_STRING; + } + } + + private CellFormatter fmt = DefaultCellFormatter.INSTANCE; + + @Test + public void formatNull() { + assertEquals(UNEX, "", fmt.format(null)); + } + + @Test + public void formatInteger() { + assertEquals(UNEX, "3", fmt.format(3)); + } + + @Test + public void formatTrue() { + assertEquals(UNEX, "true", fmt.format(true)); + } + + @Test + public void formatFalse() { + assertEquals(UNEX, "false", fmt.format(false)); + } + + @Test + public void formatString() { + assertEquals(UNEX, "FOO", fmt.format("FOO")); + } + + @Test + public void formatObject() { + assertEquals(UNEX, SOME_STRING, fmt.format(new TestClass())); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/EnumFormatterTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/EnumFormatterTest.java new file mode 100644 index 00000000..68833c90 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/EnumFormatterTest.java @@ -0,0 +1,60 @@ +/* + * 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 org.junit.Test; +import org.onosproject.ui.table.CellFormatter; + +import static org.junit.Assert.assertEquals; + +/** + * Unit tests for {@link EnumFormatter}. + */ +public class EnumFormatterTest { + + enum TestEnum { + ADDED, + PENDING_ADD, + WAITING_AUDIT_COMPLETE + } + + private CellFormatter fmt = EnumFormatter.INSTANCE; + + @Test + public void nullValue() { + assertEquals("null value", "", fmt.format(null)); + } + + @Test + public void noUnderscores() { + assertEquals("All caps", "Added", fmt.format(TestEnum.ADDED)); + } + + @Test + public void underscores() { + assertEquals("All caps with underscores", + "Pending Add", fmt.format(TestEnum.PENDING_ADD)); + } + + @Test + public void multiUnderscores() { + assertEquals("All caps with underscores", + "Waiting Audit Complete", + fmt.format(TestEnum.WAITING_AUDIT_COMPLETE)); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/HexFormatterTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/HexFormatterTest.java new file mode 100644 index 00000000..ad23b02c --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/HexFormatterTest.java @@ -0,0 +1,57 @@ +/* + * 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 org.junit.Test; +import org.onosproject.ui.table.CellFormatter; + +import static org.junit.Assert.assertEquals; + +/** + * Unit tests for {@link HexFormatter}. + */ +public class HexFormatterTest { + + private CellFormatter fmt = HexFormatter.INSTANCE; + + @Test + public void nullValue() { + assertEquals("null value", "", fmt.format(null)); + } + + @Test + public void zero() { + assertEquals("zero", "0x0", fmt.format(0)); + } + + @Test + public void one() { + assertEquals("one", "0x1", fmt.format(1)); + } + + @Test + public void ten() { + assertEquals("ten", "0xa", fmt.format(10)); + } + + @Test + public void twenty() { + assertEquals("twenty", "0x14", fmt.format(20)); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/HostLocationFormatterTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/HostLocationFormatterTest.java new file mode 100644 index 00000000..bfbe4541 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/HostLocationFormatterTest.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.ui.table.cell; + +import org.junit.Test; +import org.onosproject.net.DeviceId; +import org.onosproject.net.HostLocation; +import org.onosproject.net.PortNumber; +import org.onosproject.ui.table.CellFormatter; + +import static org.junit.Assert.assertEquals; + +/** + * Unit tests for {@link HostLocationFormatter}. + */ +public class HostLocationFormatterTest { + + private static final DeviceId DEVID = DeviceId.deviceId("foobar"); + private static final PortNumber PORT = PortNumber.portNumber(42); + private static final long TIME = 12345; + + private static final HostLocation LOC = new HostLocation(DEVID, PORT, TIME); + + private CellFormatter fmt = HostLocationFormatter.INSTANCE; + + @Test + public void basic() { + assertEquals("wrong format", "foobar/42", fmt.format(LOC)); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/TimeFormatterTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/TimeFormatterTest.java new file mode 100644 index 00000000..f41d82b3 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/table/cell/TimeFormatterTest.java @@ -0,0 +1,52 @@ +/* + * 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 org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.junit.Test; +import org.onosproject.ui.table.CellFormatter; + +import java.util.Locale; + +import static org.junit.Assert.assertTrue; + +/** + * Unit tests for {@link TimeFormatter}. + */ +public class TimeFormatterTest { + + private static final Locale LOCALE = Locale.ENGLISH; + private static final DateTimeZone ZONE = DateTimeZone.UTC; + + private static final DateTime TIME = new DateTime(2015, 5, 4, 15, 30, ZONE); + private static final String EXP_ZONE_NAME = "3:30:00 PM UTC"; + private static final String EXP_ZONE_OFFSET = "3:30:00 PM +00:00"; + + // Have to use explicit Locale and TimeZone for the unit test, so that + // irrespective of which locale and time zone the test is run in, it + // always produces the same result... + private CellFormatter fmt = + new TimeFormatter().withLocale(LOCALE).withZone(ZONE); + + @Test + public void basic() { + assertTrue("wrong format", (EXP_ZONE_NAME.equals(fmt.format(TIME)) || + EXP_ZONE_OFFSET.equals(fmt.format(TIME)))); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/BiLinkMapTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/BiLinkMapTest.java new file mode 100644 index 00000000..17fcc229 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/BiLinkMapTest.java @@ -0,0 +1,76 @@ +/* + * 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.topo; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Unit tests for {@link BiLinkMap}. + */ +public class BiLinkMapTest extends BiLinkTestBase { + + + private ConcreteLink clink; + private ConcreteLinkMap linkMap; + + @Before + public void setUp() { + linkMap = new ConcreteLinkMap(); + } + + @Test + public void basic() { + assertEquals("wrong map size", 0, linkMap.size()); + assertTrue("unexpected links", linkMap.biLinks().isEmpty()); + } + + @Test + public void addSameLinkTwice() { + linkMap.add(LINK_AB); + assertEquals("wrong map size", 1, linkMap.size()); + clink = linkMap.biLinks().iterator().next(); + assertEquals("wrong link one", LINK_AB, clink.one()); + assertNull("unexpected link two", clink.two()); + + linkMap.add(LINK_AB); + assertEquals("wrong map size", 1, linkMap.size()); + clink = linkMap.biLinks().iterator().next(); + assertEquals("wrong link one", LINK_AB, clink.one()); + assertNull("unexpected link two", clink.two()); + } + + @Test + public void addPairOfLinks() { + linkMap.add(LINK_AB); + assertEquals("wrong map size", 1, linkMap.size()); + clink = linkMap.biLinks().iterator().next(); + assertEquals("wrong link one", LINK_AB, clink.one()); + assertNull("unexpected link two", clink.two()); + + linkMap.add(LINK_BA); + assertEquals("wrong map size", 1, linkMap.size()); + clink = linkMap.biLinks().iterator().next(); + assertEquals("wrong link one", LINK_AB, clink.one()); + assertEquals("wrong link two", LINK_BA, clink.two()); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTest.java new file mode 100644 index 00000000..1acc06fa --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTest.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.ui.topo; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +/** + * Unit tests for {@link BiLink}. + */ +public class BiLinkTest extends BiLinkTestBase { + + private static final String EXP_ID_AB = "device-a/1-device-b/2"; + + private BiLink blink; + + @Test + public void basic() { + blink = new ConcreteLink(KEY_AB, LINK_AB); + assertEquals("wrong id", EXP_ID_AB, blink.linkId()); + assertEquals("wrong key", KEY_AB, blink.key()); + assertEquals("wrong link one", LINK_AB, blink.one()); + assertNull("what?", blink.two()); + + blink.setOther(LINK_BA); + assertEquals("wrong link two", LINK_BA, blink.two()); + } + + @Test(expected = NullPointerException.class) + public void nullKey() { + new ConcreteLink(null, LINK_AB); + } + + @Test(expected = NullPointerException.class) + public void nullLink() { + new ConcreteLink(KEY_AB, null); + } + + @Test(expected = NullPointerException.class) + public void nullOther() { + blink = new ConcreteLink(KEY_AB, LINK_AB); + blink.setOther(null); + } +} + diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTestBase.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTestBase.java new file mode 100644 index 00000000..b5bd41ef --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/BiLinkTestBase.java @@ -0,0 +1,98 @@ +/* + * 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.topo; + +import org.onosproject.net.Annotations; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.LinkKey; +import org.onosproject.net.PortNumber; +import org.onosproject.net.provider.ProviderId; + +/** + * Base class for unit tests of {@link BiLink} and {@link BiLinkMap}. + */ +public abstract class BiLinkTestBase { + + protected static class FakeLink implements Link { + private final ConnectPoint src; + private final ConnectPoint dst; + + FakeLink(ConnectPoint src, ConnectPoint dst) { + this.src = src; + this.dst = dst; + } + + @Override public ConnectPoint src() { + return src; + } + @Override public ConnectPoint dst() { + return dst; + } + + @Override public Type type() { + return null; + } + @Override public State state() { + return null; + } + @Override public boolean isDurable() { + return false; + } + @Override public Annotations annotations() { + return null; + } + @Override public ProviderId providerId() { + return null; + } + } + + protected static final DeviceId DEV_A_ID = DeviceId.deviceId("device-A"); + protected static final DeviceId DEV_B_ID = DeviceId.deviceId("device-B"); + protected static final PortNumber PORT_1 = PortNumber.portNumber(1); + protected static final PortNumber PORT_2 = PortNumber.portNumber(2); + + protected static final ConnectPoint CP_A1 = new ConnectPoint(DEV_A_ID, PORT_1); + protected static final ConnectPoint CP_B2 = new ConnectPoint(DEV_B_ID, PORT_2); + + protected static final LinkKey KEY_AB = LinkKey.linkKey(CP_A1, CP_B2); + protected static final LinkKey KEY_BA = LinkKey.linkKey(CP_B2, CP_A1); + + protected static final Link LINK_AB = new FakeLink(CP_A1, CP_B2); + protected static final Link LINK_BA = new FakeLink(CP_B2, CP_A1); + + protected static class ConcreteLink extends BiLink { + public ConcreteLink(LinkKey key, Link link) { + super(key, link); + } + @Override + public LinkHighlight highlight(Enum type) { + return null; + } + } + + protected static class ConcreteLinkMap extends BiLinkMap { + @Override + public ConcreteLink create(LinkKey key, Link link) { + return new ConcreteLink(key, link); + } + } + + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/ButtonIdTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/ButtonIdTest.java new file mode 100644 index 00000000..04c6dc18 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/ButtonIdTest.java @@ -0,0 +1,56 @@ +/* + * 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.topo; + +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Unit tests for {@link ButtonId}. + */ +public class ButtonIdTest { + + private static final String ID1 = "id-1"; + private static final String ID2 = "id-2"; + + private ButtonId b1, b2; + + + @Test + public void basic() { + b1 = new ButtonId(ID1); + } + + @Test + public void same() { + b1 = new ButtonId(ID1); + b2 = new ButtonId(ID1); + assertFalse("same ref?", b1 == b2); + assertTrue("not equal?", b1.equals(b2)); + } + + @Test + public void notSame() { + b1 = new ButtonId(ID1); + b2 = new ButtonId(ID2); + assertFalse("same ref?", b1 == b2); + assertFalse("equal?", b1.equals(b2)); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/HighlightsTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/HighlightsTest.java new file mode 100644 index 00000000..7d6dfe67 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/HighlightsTest.java @@ -0,0 +1,91 @@ +/* + * 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.topo; + +import org.junit.Before; +import org.junit.Test; +import org.onosproject.ui.topo.Highlights.Amount; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Unit tests for {@link Highlights}. + */ +public class HighlightsTest { + + private static final String DEV_1 = "dev-1"; + private static final String DEV_2 = "dev-2"; + private static final String HOST_A = "Host...A"; + + private Highlights highlights; + private DeviceHighlight dh1; + private DeviceHighlight dh2; + private HostHighlight hha; + + @Before + public void setUp() { + highlights = new Highlights(); + } + + @Test + public void basic() { + assertEquals("devices", 0, highlights.devices().size()); + assertEquals("hosts", 0, highlights.hosts().size()); + assertEquals("links", 0, highlights.links().size()); + assertEquals("sudue", Amount.ZERO, highlights.subdueLevel()); + } + + @Test + public void coupleOfDevices() { + dh1 = new DeviceHighlight(DEV_1); + dh2 = new DeviceHighlight(DEV_2); + + highlights.add(dh1); + highlights.add(dh2); + assertTrue("missing dh1", highlights.devices().contains(dh1)); + assertTrue("missing dh2", highlights.devices().contains(dh2)); + } + + @Test + public void alternateSubdue() { + highlights.subdueAllElse(Amount.MINIMALLY); + assertEquals("wrong level", Amount.MINIMALLY, highlights.subdueLevel()); + } + + @Test + public void highlightRetrieval() { + dh1 = new DeviceHighlight(DEV_1); + hha = new HostHighlight(HOST_A); + highlights.add(dh1) + .add(hha); + + assertNull("dev as host", highlights.getHost(DEV_1)); + assertNull("host as dev", highlights.getDevice(HOST_A)); + + assertEquals("missed dev as dev", dh1, highlights.getDevice(DEV_1)); + assertEquals("missed dev as node", dh1, highlights.getNode(DEV_1)); + + assertEquals("missed host as host", hha, highlights.getHost(HOST_A)); + assertEquals("missed host as node", hha, highlights.getNode(HOST_A)); + } + + // NOTE: further unit tests involving the Highlights class are done + // in TopoJsonTest. +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/LinkHighlightTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/LinkHighlightTest.java new file mode 100644 index 00000000..205f08ce --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/LinkHighlightTest.java @@ -0,0 +1,116 @@ +/* + * 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.topo; + +import org.junit.Test; + +import java.util.Iterator; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.onosproject.ui.topo.LinkHighlight.Flavor.*; + +/** + * Unit tests for {@link LinkHighlight}. + */ +public class LinkHighlightTest { + + private static final String LINK_ID = "link-id-for-testing"; + private static final String LABEL = "some label"; + private static final String EMPTY = ""; + private static final String CUSTOM = "custom"; + private static final String ANIMATED = "animated"; + private static final String OPTICAL = "optical"; + + private LinkHighlight lh; + + @Test + public void basic() { + lh = new LinkHighlight(LINK_ID, NO_HIGHLIGHT); + + assertEquals("wrong flavor", NO_HIGHLIGHT, lh.flavor()); + assertTrue("unexpected mods", lh.mods().isEmpty()); + assertEquals("wrong css", "plain", lh.cssClasses()); + assertEquals("wrong label", EMPTY, lh.label()); + } + + @Test + public void primaryOptical() { + lh = new LinkHighlight(LINK_ID, PRIMARY_HIGHLIGHT) + .addMod(LinkHighlight.MOD_OPTICAL); + + assertEquals("wrong flavor", PRIMARY_HIGHLIGHT, lh.flavor()); + assertEquals("missing mod", 1, lh.mods().size()); + Mod m = lh.mods().iterator().next(); + assertEquals("wrong mod", LinkHighlight.MOD_OPTICAL, m); + assertEquals("wrong css", "primary optical", lh.cssClasses()); + assertEquals("wrong label", EMPTY, lh.label()); + } + + @Test + public void secondaryAnimatedWithLabel() { + lh = new LinkHighlight(LINK_ID, SECONDARY_HIGHLIGHT) + .addMod(LinkHighlight.MOD_ANIMATED) + .setLabel(LABEL); + + assertEquals("wrong flavor", SECONDARY_HIGHLIGHT, lh.flavor()); + assertEquals("missing mod", 1, lh.mods().size()); + Mod m = lh.mods().iterator().next(); + assertEquals("wrong mod", LinkHighlight.MOD_ANIMATED, m); + assertEquals("wrong css", "secondary animated", lh.cssClasses()); + assertEquals("wrong label", LABEL, lh.label()); + } + + @Test + public void customMod() { + lh = new LinkHighlight(LINK_ID, PRIMARY_HIGHLIGHT) + .addMod(new Mod(CUSTOM)); + + assertEquals("missing mod", 1, lh.mods().size()); + Mod m = lh.mods().iterator().next(); + assertEquals("wrong mod", CUSTOM, m.toString()); + assertEquals("wrong css", "primary custom", lh.cssClasses()); + } + + @Test + public void severalMods() { + lh = new LinkHighlight(LINK_ID, SECONDARY_HIGHLIGHT) + .addMod(LinkHighlight.MOD_OPTICAL) + .addMod(LinkHighlight.MOD_ANIMATED) + .addMod(new Mod(CUSTOM)); + + assertEquals("missing mods", 3, lh.mods().size()); + Iterator iter = lh.mods().iterator(); + // NOTE: we know we are using TreeSet as backing => sorted order + assertEquals("wrong mod", ANIMATED, iter.next().toString()); + assertEquals("wrong mod", CUSTOM, iter.next().toString()); + assertEquals("wrong mod", OPTICAL, iter.next().toString()); + assertEquals("wrong css", "secondary animated custom optical", lh.cssClasses()); + } + + @Test(expected = NullPointerException.class) + public void noFlavor() { + new LinkHighlight(LINK_ID, null); + } + + @Test(expected = NullPointerException.class) + public void noIdentity() { + new LinkHighlight(null, PRIMARY_HIGHLIGHT); + } + +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/ModTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/ModTest.java new file mode 100644 index 00000000..bb40279c --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/ModTest.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.ui.topo; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Unit tests for {@link Mod}. + */ +public class ModTest { + + private static final String AAA = "aaa"; + private static final String BBB = "bbb"; + + private Mod mod1; + private Mod mod2; + + @Test(expected = NullPointerException.class) + public void nullId() { + new Mod(null); + } + + @Test + public void basic() { + mod1 = new Mod(AAA); + assertEquals("wrong id", AAA, mod1.toString()); + } + + @Test + public void equivalence() { + mod1 = new Mod(AAA); + mod2 = new Mod(AAA); + assertNotSame("oops", mod1, mod2); + assertEquals("not equivalent", mod1, mod2); + } + + @Test + public void comparable() { + mod1 = new Mod(AAA); + mod2 = new Mod(BBB); + assertNotEquals("what?", mod1, mod2); + assertTrue(mod1.compareTo(mod2) < 0); + assertTrue(mod2.compareTo(mod1) > 0); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/NodeSelectionTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/NodeSelectionTest.java new file mode 100644 index 00000000..60cada45 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/NodeSelectionTest.java @@ -0,0 +1,349 @@ +/* + * 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.topo; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.junit.Test; +import org.onlab.packet.ChassisId; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; +import org.onosproject.net.Annotations; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Host; +import org.onosproject.net.HostId; +import org.onosproject.net.HostLocation; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.device.DeviceServiceAdapter; +import org.onosproject.net.host.HostService; +import org.onosproject.net.host.HostServiceAdapter; +import org.onosproject.net.provider.ProviderId; + +import java.util.Set; + +import static org.junit.Assert.*; + +/** + * Unit tests for {@link NodeSelection}. + */ +public class NodeSelectionTest { + + private static class FakeDevice implements Device { + + private final DeviceId id; + + FakeDevice(DeviceId id) { + this.id = id; + } + + @Override + public DeviceId id() { + return id; + } + + @Override + public Type type() { + return null; + } + + @Override + public String manufacturer() { + return null; + } + + @Override + public String hwVersion() { + return null; + } + + @Override + public String swVersion() { + return null; + } + + @Override + public String serialNumber() { + return null; + } + + @Override + public ChassisId chassisId() { + return null; + } + + @Override + public Annotations annotations() { + return null; + } + + @Override + public ProviderId providerId() { + return null; + } + } + + private static class FakeHost implements Host { + + private final HostId id; + + FakeHost(HostId id) { + this.id = id; + } + + @Override + public HostId id() { + return id; + } + + @Override + public MacAddress mac() { + return null; + } + + @Override + public VlanId vlan() { + return null; + } + + @Override + public Set ipAddresses() { + return null; + } + + @Override + public HostLocation location() { + return null; + } + + @Override + public Annotations annotations() { + return null; + } + + @Override + public ProviderId providerId() { + return null; + } + } + + + + private final ObjectMapper mapper = new ObjectMapper(); + + private static final String IDS = "ids"; + private static final String HOVER = "hover"; + + private static final DeviceId DEVICE_1_ID = DeviceId.deviceId("Device-1"); + private static final DeviceId DEVICE_2_ID = DeviceId.deviceId("Device-2"); + private static final HostId HOST_A_ID = HostId.hostId("aa:aa:aa:aa:aa:aa/1"); + private static final HostId HOST_B_ID = HostId.hostId("bb:bb:bb:bb:bb:bb/2"); + + private static final Device DEVICE_1 = new FakeDevice(DEVICE_1_ID); + private static final Device DEVICE_2 = new FakeDevice(DEVICE_2_ID); + private static final Host HOST_A = new FakeHost(HOST_A_ID); + private static final Host HOST_B = new FakeHost(HOST_B_ID); + + // ================== + // == FAKE SERVICES + private static class FakeDevices extends DeviceServiceAdapter { + @Override + public Device getDevice(DeviceId deviceId) { + if (DEVICE_1_ID.equals(deviceId)) { + return DEVICE_1; + } + if (DEVICE_2_ID.equals(deviceId)) { + return DEVICE_2; + } + return null; + } + } + + private static class FakeHosts extends HostServiceAdapter { + @Override + public Host getHost(HostId hostId) { + if (HOST_A_ID.equals(hostId)) { + return HOST_A; + } + if (HOST_B_ID.equals(hostId)) { + return HOST_B; + } + return null; + } + } + + private DeviceService deviceService = new FakeDevices(); + private HostService hostService = new FakeHosts(); + + private NodeSelection ns; + + private ObjectNode objectNode() { + return mapper.createObjectNode(); + } + + private ArrayNode arrayNode() { + return mapper.createArrayNode(); + } + + private NodeSelection createNodeSelection(ObjectNode payload) { + return new NodeSelection(payload, deviceService, hostService); + } + + // selection JSON payload creation methods + private ObjectNode emptySelection() { + ObjectNode payload = objectNode(); + ArrayNode ids = arrayNode(); + payload.set(IDS, ids); + return payload; + } + + private ObjectNode oneDeviceSelected() { + ObjectNode payload = objectNode(); + ArrayNode ids = arrayNode(); + payload.set(IDS, ids); + ids.add(DEVICE_1_ID.toString()); + return payload; + } + + private ObjectNode oneHostSelected() { + ObjectNode payload = objectNode(); + ArrayNode ids = arrayNode(); + payload.set(IDS, ids); + ids.add(HOST_A_ID.toString()); + return payload; + } + + private ObjectNode twoHostsOneDeviceSelected() { + ObjectNode payload = objectNode(); + ArrayNode ids = arrayNode(); + payload.set(IDS, ids); + ids.add(HOST_A_ID.toString()); + ids.add(DEVICE_1_ID.toString()); + ids.add(HOST_B_ID.toString()); + return payload; + } + + private ObjectNode oneHostAndHoveringDeviceSelected() { + ObjectNode payload = objectNode(); + ArrayNode ids = arrayNode(); + payload.set(IDS, ids); + ids.add(HOST_A_ID.toString()); + payload.put(HOVER, DEVICE_2_ID.toString()); + return payload; + } + + private ObjectNode twoDevicesOneHostAndHoveringHostSelected() { + ObjectNode payload = objectNode(); + ArrayNode ids = arrayNode(); + payload.set(IDS, ids); + ids.add(HOST_A_ID.toString()); + ids.add(DEVICE_1_ID.toString()); + ids.add(DEVICE_2_ID.toString()); + payload.put(HOVER, HOST_B_ID.toString()); + return payload; + } + + + @Test + public void basic() { + ns = createNodeSelection(emptySelection()); + assertEquals("unexpected devices", 0, ns.devices().size()); + assertEquals("unexpected devices w/hover", 0, ns.devicesWithHover().size()); + assertEquals("unexpected hosts", 0, ns.hosts().size()); + assertEquals("unexpected hosts w/hover", 0, ns.hostsWithHover().size()); + assertTrue("unexpected selection", ns.none()); + assertNull("hover?", ns.hovered()); + } + + @Test + public void oneDevice() { + ns = createNodeSelection(oneDeviceSelected()); + assertEquals("missing device", 1, ns.devices().size()); + assertTrue("missing device 1", ns.devices().contains(DEVICE_1)); + assertEquals("missing device w/hover", 1, ns.devicesWithHover().size()); + assertTrue("missing device 1 w/hover", ns.devicesWithHover().contains(DEVICE_1)); + assertEquals("unexpected hosts", 0, ns.hosts().size()); + assertEquals("unexpected hosts w/hover", 0, ns.hostsWithHover().size()); + assertFalse("unexpected selection", ns.none()); + assertNull("hover?", ns.hovered()); + } + + @Test + public void oneHost() { + ns = createNodeSelection(oneHostSelected()); + assertEquals("unexpected devices", 0, ns.devices().size()); + assertEquals("unexpected devices w/hover", 0, ns.devicesWithHover().size()); + assertEquals("missing host", 1, ns.hosts().size()); + assertTrue("missing host A", ns.hosts().contains(HOST_A)); + assertEquals("missing host w/hover", 1, ns.hostsWithHover().size()); + assertTrue("missing host A w/hover", ns.hostsWithHover().contains(HOST_A)); + assertFalse("unexpected selection", ns.none()); + assertNull("hover?", ns.hovered()); + } + + @Test + public void twoHostsOneDevice() { + ns = createNodeSelection(twoHostsOneDeviceSelected()); + assertEquals("missing device", 1, ns.devices().size()); + assertTrue("missing device 1", ns.devices().contains(DEVICE_1)); + assertEquals("missing device w/hover", 1, ns.devicesWithHover().size()); + assertTrue("missing device 1 w/hover", ns.devicesWithHover().contains(DEVICE_1)); + assertEquals("unexpected hosts", 2, ns.hosts().size()); + assertTrue("missing host A", ns.hosts().contains(HOST_A)); + assertTrue("missing host B", ns.hosts().contains(HOST_B)); + assertEquals("unexpected hosts w/hover", 2, ns.hostsWithHover().size()); + assertTrue("missing host A w/hover", ns.hostsWithHover().contains(HOST_A)); + assertTrue("missing host B w/hover", ns.hostsWithHover().contains(HOST_B)); + assertFalse("unexpected selection", ns.none()); + assertNull("hover?", ns.hovered()); + } + + @Test + public void oneHostAndHoveringDevice() { + ns = createNodeSelection(oneHostAndHoveringDeviceSelected()); + assertEquals("unexpected devices", 0, ns.devices().size()); + assertEquals("unexpected devices w/hover", 1, ns.devicesWithHover().size()); + assertTrue("missing device 2 w/hover", ns.devicesWithHover().contains(DEVICE_2)); + assertEquals("missing host", 1, ns.hosts().size()); + assertTrue("missing host A", ns.hosts().contains(HOST_A)); + assertEquals("missing host w/hover", 1, ns.hostsWithHover().size()); + assertTrue("missing host A w/hover", ns.hostsWithHover().contains(HOST_A)); + assertFalse("unexpected selection", ns.none()); + assertEquals("missing hover device 2", DEVICE_2, ns.hovered()); + } + + @Test + public void twoDevicesOneHostAndHoveringHost() { + ns = createNodeSelection(twoDevicesOneHostAndHoveringHostSelected()); + assertEquals("missing devices", 2, ns.devices().size()); + assertTrue("missing device 1", ns.devices().contains(DEVICE_1)); + assertTrue("missing device 2", ns.devices().contains(DEVICE_2)); + assertEquals("missing devices w/hover", 2, ns.devicesWithHover().size()); + assertTrue("missing device 1 w/hover", ns.devicesWithHover().contains(DEVICE_1)); + assertTrue("missing device 2 w/hover", ns.devicesWithHover().contains(DEVICE_2)); + assertEquals("missing host", 1, ns.hosts().size()); + assertTrue("missing host A", ns.hosts().contains(HOST_A)); + assertEquals("missing host w/hover", 2, ns.hostsWithHover().size()); + assertTrue("missing host A w/hover", ns.hostsWithHover().contains(HOST_A)); + assertTrue("missing host B w/hover", ns.hostsWithHover().contains(HOST_B)); + assertFalse("unexpected selection", ns.none()); + assertEquals("missing hover host B", HOST_B, ns.hovered()); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/PropertyPanelTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/PropertyPanelTest.java new file mode 100644 index 00000000..b08ee4dc --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/PropertyPanelTest.java @@ -0,0 +1,238 @@ +/* + * 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.topo; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.onosproject.ui.topo.PropertyPanel.Prop; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import static org.junit.Assert.*; + +/** + * Unit tests for {@link PropertyPanel}. + */ +public class PropertyPanelTest { + + private static final String TITLE_ORIG = "Original Title"; + private static final String TYPE_ORIG = "Original type ID"; + private static final String TITLE_NEW = "New Title"; + private static final String TYPE_NEW = "New type"; + private static final String SOME_IDENTIFICATION = "It's Me!"; + + private static final String KEY_A = "A"; + private static final String KEY_B = "B"; + private static final String KEY_C = "C"; + private static final String SEP = "-"; + private static final String KEY_Z = "Z"; + private static final String VALUE_A = "Hay"; + private static final String VALUE_B = "Bee"; + private static final String VALUE_C = "Sea"; + private static final String VALUE_Z = "Zed"; + + private static final Map PROP_MAP = new HashMap<>(); + + private static class FooClass { + private final String s; + FooClass(String s) { + this.s = s; + } + + @Override + public String toString() { + return ">" + s + "<"; + } + } + + private PropertyPanel pp; + + + + @BeforeClass + public static void setUpClass() { + PROP_MAP.put(KEY_A, new Prop(KEY_A, VALUE_A)); + PROP_MAP.put(KEY_B, new Prop(KEY_B, VALUE_B)); + PROP_MAP.put(KEY_C, new Prop(KEY_C, VALUE_C)); + PROP_MAP.put(KEY_Z, new Prop(KEY_Z, VALUE_Z)); + PROP_MAP.put(SEP, new PropertyPanel.Separator()); + } + + @Test + public void basic() { + pp = new PropertyPanel(TITLE_ORIG, TYPE_ORIG); + assertEquals("wrong title", TITLE_ORIG, pp.title()); + assertEquals("wrong type", TYPE_ORIG, pp.typeId()); + assertNull("id?", pp.id()); + assertEquals("unexpected props", 0, pp.properties().size()); + assertEquals("unexpected buttons", 0, pp.buttons().size()); + } + + @Test + public void changeTitle() { + basic(); + pp.title(TITLE_NEW); + assertEquals("wrong title", TITLE_NEW, pp.title()); + } + + @Test + public void changeType() { + basic(); + pp.typeId(TYPE_NEW); + assertEquals("wrong type", TYPE_NEW, pp.typeId()); + } + + @Test + public void setId() { + basic(); + pp.id(SOME_IDENTIFICATION); + assertEquals("wrong id", SOME_IDENTIFICATION, pp.id()); + } + + private void validateProps(String... keys) { + Iterator iter = pp.properties().iterator(); + for (String k: keys) { + Prop exp = PROP_MAP.get(k); + Prop act = iter.next(); + assertEquals("Bad prop sequence", exp, act); + } + } + + private void validateProp(String key, String expValue) { + Iterator iter = pp.properties().iterator(); + Prop prop = null; + while (iter.hasNext()) { + Prop p = iter.next(); + if (p.key().equals(key)) { + prop = p; + break; + } + } + if (prop == null) { + fail("no prop found with key: " + key); + } + assertEquals("Wrong prop value", expValue, prop.value()); + } + + @Test + public void props() { + basic(); + pp.addProp(KEY_A, VALUE_A) + .addProp(KEY_B, VALUE_B) + .addProp(KEY_C, VALUE_C); + assertEquals("bad props", 3, pp.properties().size()); + validateProps(KEY_A, KEY_B, KEY_C); + } + + @Test + public void separator() { + props(); + pp.addSeparator() + .addProp(KEY_Z, VALUE_Z); + + assertEquals("bad props", 5, pp.properties().size()); + validateProps(KEY_A, KEY_B, KEY_C, SEP, KEY_Z); + } + + @Test + public void removeAllProps() { + props(); + assertEquals("wrong props", 3, pp.properties().size()); + pp.removeAllProps(); + assertEquals("unexpected props", 0, pp.properties().size()); + } + + @Test + public void adjustProps() { + props(); + pp.removeProps(KEY_B, KEY_A); + pp.addProp(KEY_Z, VALUE_Z); + validateProps(KEY_C, KEY_Z); + } + + @Test + public void intValues() { + basic(); + pp.addProp(KEY_A, 200) + .addProp(KEY_B, 2000) + .addProp(KEY_C, 1234567); + + validateProp(KEY_A, "200"); + validateProp(KEY_B, "2,000"); + validateProp(KEY_C, "1,234,567"); + } + + @Test + public void longValues() { + basic(); + pp.addProp(KEY_A, 200L) + .addProp(KEY_B, 2000L) + .addProp(KEY_C, 1234567L) + .addProp(KEY_Z, Long.MAX_VALUE); + + validateProp(KEY_A, "200"); + validateProp(KEY_B, "2,000"); + validateProp(KEY_C, "1,234,567"); + validateProp(KEY_Z, "9,223,372,036,854,775,807"); + } + + @Test + public void objectValue() { + basic(); + pp.addProp(KEY_A, new FooClass("a")) + .addProp(KEY_B, new FooClass("bxyyzy"), "[xz]"); + + validateProp(KEY_A, ">a<"); + validateProp(KEY_B, ">byyy<"); + } + + private static final ButtonId BD_A = new ButtonId(KEY_A); + private static final ButtonId BD_B = new ButtonId(KEY_B); + private static final ButtonId BD_C = new ButtonId(KEY_C); + private static final ButtonId BD_Z = new ButtonId(KEY_Z); + + private void verifyButtons(String... keys) { + Iterator iter = pp.buttons().iterator(); + for (String k: keys) { + assertEquals("wrong button", k, iter.next().id()); + } + assertFalse("too many buttons", iter.hasNext()); + } + + @Test + public void buttons() { + basic(); + pp.addButton(BD_A) + .addButton(BD_B); + assertEquals("wrong buttons", 2, pp.buttons().size()); + verifyButtons(KEY_A, KEY_B); + + pp.removeButtons(BD_B) + .addButton(BD_C) + .addButton(BD_Z); + assertEquals("wrong buttons", 3, pp.buttons().size()); + verifyButtons(KEY_A, KEY_C, KEY_Z); + + pp.removeAllButtons() + .addButton(BD_B); + assertEquals("wrong buttons", 1, pp.buttons().size()); + verifyButtons(KEY_B); + } +} diff --git a/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/TopoJsonTest.java b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/TopoJsonTest.java new file mode 100644 index 00000000..6a3bfa43 --- /dev/null +++ b/framework/src/onos/core/api/src/test/java/org/onosproject/ui/topo/TopoJsonTest.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.ui.topo; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.junit.Test; +import org.onosproject.ui.JsonUtils; +import org.onosproject.ui.topo.Highlights.Amount; + +import static org.junit.Assert.assertEquals; + +/** + * Unit tests for {@link TopoJson}. + */ +public class TopoJsonTest { + + private ObjectNode payload; + + private void checkArrayLength(String key, int expLen) { + ArrayNode a = (ArrayNode) payload.get(key); + assertEquals("wrong size: " + key, expLen, a.size()); + } + + private void checkEmptyArrays() { + checkArrayLength(TopoJson.DEVICES, 0); + checkArrayLength(TopoJson.HOSTS, 0); + checkArrayLength(TopoJson.LINKS, 0); + } + + @Test + public void basicHighlights() { + Highlights h = new Highlights(); + payload = TopoJson.json(h); + checkEmptyArrays(); + String subdue = JsonUtils.string(payload, TopoJson.SUBDUE); + assertEquals("subdue", "", subdue); + } + + @Test + public void subdueMinimalHighlights() { + Highlights h = new Highlights().subdueAllElse(Amount.MINIMALLY); + payload = TopoJson.json(h); + checkEmptyArrays(); + String subdue = JsonUtils.string(payload, TopoJson.SUBDUE); + assertEquals("not min", "min", subdue); + } + + @Test + public void subdueMaximalHighlights() { + Highlights h = new Highlights().subdueAllElse(Amount.MAXIMALLY); + payload = TopoJson.json(h); + checkEmptyArrays(); + String subdue = JsonUtils.string(payload, TopoJson.SUBDUE); + assertEquals("not max", "max", subdue); + } +} diff --git a/framework/src/onos/core/api/src/test/resources/css.html b/framework/src/onos/core/api/src/test/resources/css.html new file mode 100644 index 00000000..3079957b --- /dev/null +++ b/framework/src/onos/core/api/src/test/resources/css.html @@ -0,0 +1,2 @@ +foo-css +bar-css \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/resources/custom/css.html b/framework/src/onos/core/api/src/test/resources/custom/css.html new file mode 100644 index 00000000..e67f4a2b --- /dev/null +++ b/framework/src/onos/core/api/src/test/resources/custom/css.html @@ -0,0 +1 @@ +custom-css diff --git a/framework/src/onos/core/api/src/test/resources/custom/js.html b/framework/src/onos/core/api/src/test/resources/custom/js.html new file mode 100644 index 00000000..f87844b1 --- /dev/null +++ b/framework/src/onos/core/api/src/test/resources/custom/js.html @@ -0,0 +1 @@ +custom-js \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/resources/js.html b/framework/src/onos/core/api/src/test/resources/js.html new file mode 100644 index 00000000..50b63b34 --- /dev/null +++ b/framework/src/onos/core/api/src/test/resources/js.html @@ -0,0 +1,2 @@ +foo-js +bar-js \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.1.xml b/framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.1.xml new file mode 100644 index 00000000..e4490450 --- /dev/null +++ b/framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.1.xml @@ -0,0 +1,33 @@ + + + + + + + + + ding + bat + + + + v1 + v2 + + \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.bad.xml b/framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.bad.xml new file mode 100644 index 00000000..5815ba38 --- /dev/null +++ b/framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.bad.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.noclass.xml b/framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.noclass.xml new file mode 100644 index 00000000..e46b42e3 --- /dev/null +++ b/framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.noclass.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file diff --git a/framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.noconstructor.xml b/framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.noconstructor.xml new file mode 100644 index 00000000..873656d8 --- /dev/null +++ b/framework/src/onos/core/api/src/test/resources/org/onosproject/net/driver/drivers.noconstructor.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file diff --git a/framework/src/onos/core/common/pom.xml b/framework/src/onos/core/common/pom.xml new file mode 100644 index 00000000..71c0fe40 --- /dev/null +++ b/framework/src/onos/core/common/pom.xml @@ -0,0 +1,58 @@ + + + + 4.0.0 + + + org.onosproject + onos-core + 1.3.0-SNAPSHOT + ../pom.xml + + + onos-core-common + bundle + + ONOS utilities common to the core modules + + + + org.osgi + org.osgi.core + + + org.onosproject + onos-api + + + + org.onosproject + onos-api + tests + test + + + + org.easymock + easymock + test + + + + diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/AnnotatedCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/AnnotatedCodec.java new file mode 100644 index 00000000..8c714625 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/AnnotatedCodec.java @@ -0,0 +1,64 @@ +/* + * Copyright 2014-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 com.fasterxml.jackson.databind.node.ObjectNode; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.Annotated; +import org.onosproject.net.Annotations; +import org.onosproject.net.DefaultAnnotations; + +/** + * Base JSON codec for annotated entities. + */ +public abstract class AnnotatedCodec extends JsonCodec { + + /** + * Adds JSON encoding of the given item annotations to the specified node. + * + * @param node node to add annotations to + * @param entity annotated entity + * @param context encode context + * @return the given node + */ + protected ObjectNode annotate(ObjectNode node, T entity, CodecContext context) { + if (!entity.annotations().keys().isEmpty()) { + JsonCodec codec = context.codec(Annotations.class); + node.set("annotations", codec.encode(entity.annotations(), context)); + } + return node; + } + + /** + * Extracts annotations of given Object. + * + * @param objNode annotated JSON object node + * @param context decode context + * @return extracted Annotations + */ + protected Annotations extractAnnotations(ObjectNode objNode, CodecContext context) { + + JsonCodec codec = context.codec(Annotations.class); + if (objNode.has("annotations") && objNode.isObject()) { + return codec.decode(get(objNode, "annotations"), context); + } else { + return DefaultAnnotations.EMPTY; + } + } + +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/AnnotationsCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/AnnotationsCodec.java new file mode 100644 index 00000000..de6ca1b9 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/AnnotationsCodec.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014-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 com.fasterxml.jackson.databind.node.ObjectNode; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.Annotations; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.DefaultAnnotations.Builder; + +/** + * Annotations JSON codec. + */ +public final class AnnotationsCodec extends JsonCodec { + + @Override + public ObjectNode encode(Annotations annotations, CodecContext context) { + ObjectNode result = context.mapper().createObjectNode(); + for (String key : annotations.keys()) { + result.put(key, annotations.value(key)); + } + return result; + } + + @Override + public Annotations decode(ObjectNode json, CodecContext context) { + Builder builder = DefaultAnnotations.builder(); + + json.fields().forEachRemaining(e -> + builder.set(e.getKey(), e.getValue().asText())); + + return builder.build(); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ApplicationCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ApplicationCodec.java new file mode 100644 index 00000000..b2cab094 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ApplicationCodec.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.codec.impl; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.app.ApplicationService; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.core.Application; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Application JSON codec. + */ +public final class ApplicationCodec extends JsonCodec { + + @Override + public ObjectNode encode(Application app, CodecContext context) { + checkNotNull(app, "Application cannot be null"); + ApplicationService service = context.getService(ApplicationService.class); + ObjectNode result = context.mapper().createObjectNode() + .put("name", app.id().name()) + .put("id", app.id().id()) + .put("version", app.version().toString()) + .put("description", app.description()) + .put("origin", app.origin()) + .put("permissions", app.permissions().toString()) + .put("featuresRepo", app.featuresRepo().isPresent() ? + app.featuresRepo().get().toString() : "") + .put("features", app.features().toString()) + .put("state", service.getState(app.id()).toString()); + return result; + } + +} 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 new file mode 100644 index 00000000..eb53152e --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CodecManager.java @@ -0,0 +1,132 @@ +/* + * Copyright 2014-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 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.Service; +import org.onlab.packet.Ethernet; +import org.onosproject.cluster.ControllerNode; +import org.onosproject.codec.CodecService; +import org.onosproject.codec.JsonCodec; +import org.onosproject.core.Application; +import org.onosproject.net.Annotations; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Device; +import org.onosproject.net.Host; +import org.onosproject.net.HostLocation; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +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.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.group.Group; +import org.onosproject.net.group.GroupBucket; +import org.onosproject.net.intent.ConnectivityIntent; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.HostToHostIntent; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.PointToPointIntent; +import org.onosproject.net.statistic.Load; +import org.onosproject.net.topology.Topology; +import org.onosproject.net.topology.TopologyCluster; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Implementation of the JSON codec brokering service. + */ +@Component(immediate = true) +@Service +public class CodecManager implements CodecService { + + private static Logger log = LoggerFactory.getLogger(CodecManager.class); + + private final Map, JsonCodec> codecs = new ConcurrentHashMap<>(); + + @Activate + public void activate() { + codecs.clear(); + registerCodec(Application.class, new ApplicationCodec()); + registerCodec(ControllerNode.class, new ControllerNodeCodec()); + registerCodec(Annotations.class, new AnnotationsCodec()); + registerCodec(Device.class, new DeviceCodec()); + registerCodec(Port.class, new PortCodec()); + registerCodec(ConnectPoint.class, new ConnectPointCodec()); + registerCodec(Link.class, new LinkCodec()); + registerCodec(Host.class, new HostCodec()); + registerCodec(HostLocation.class, new HostLocationCodec()); + registerCodec(HostToHostIntent.class, new HostToHostIntentCodec()); + registerCodec(PointToPointIntent.class, new PointToPointIntentCodec()); + registerCodec(Intent.class, new IntentCodec()); + registerCodec(ConnectivityIntent.class, new ConnectivityIntentCodec()); + registerCodec(FlowEntry.class, new FlowEntryCodec()); + registerCodec(FlowRule.class, new FlowRuleCodec()); + registerCodec(TrafficTreatment.class, new TrafficTreatmentCodec()); + registerCodec(TrafficSelector.class, new TrafficSelectorCodec()); + registerCodec(Instruction.class, new InstructionCodec()); + registerCodec(Criterion.class, new CriterionCodec()); + registerCodec(Ethernet.class, new EthernetCodec()); + registerCodec(Constraint.class, new ConstraintCodec()); + registerCodec(Topology.class, new TopologyCodec()); + registerCodec(TopologyCluster.class, new TopologyClusterCodec()); + registerCodec(Path.class, new PathCodec()); + registerCodec(Group.class, new GroupCodec()); + registerCodec(Driver.class, new DriverCodec()); + registerCodec(GroupBucket.class, new GroupBucketCodec()); + registerCodec(Load.class, new LoadCodec()); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + codecs.clear(); + log.info("Stopped"); + } + + @Override + public Set> getCodecs() { + return ImmutableSet.copyOf(codecs.keySet()); + } + + @Override + @SuppressWarnings("unchecked") + public JsonCodec getCodec(Class entityClass) { + return codecs.get(entityClass); + } + + @Override + public void registerCodec(Class entityClass, JsonCodec codec) { + codecs.putIfAbsent(entityClass, codec); + } + + @Override + public void unregisterCodec(Class entityClass) { + codecs.remove(entityClass); + } + +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ConnectPointCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ConnectPointCodec.java new file mode 100644 index 00000000..ac23ef89 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ConnectPointCodec.java @@ -0,0 +1,74 @@ +/* + * Copyright 2014-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 com.fasterxml.jackson.databind.node.ObjectNode; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.ElementId; +import org.onosproject.net.HostId; +import org.onosproject.net.PortNumber; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Connection point JSON codec. + */ +public final class ConnectPointCodec extends JsonCodec { + + // JSON field names + private static final String ELEMENT_HOST = "host"; + private static final String ELEMENT_DEVICE = "device"; + private static final String PORT = "port"; + + @Override + public ObjectNode encode(ConnectPoint point, CodecContext context) { + checkNotNull(point, "Connect point cannot be null"); + ObjectNode root = context.mapper().createObjectNode() + .put(PORT, point.port().toString()); + + if (point.elementId() instanceof DeviceId) { + root.put(ELEMENT_DEVICE, point.deviceId().toString()); + } else if (point.elementId() instanceof HostId) { + root.put(ELEMENT_HOST, point.hostId().toString()); + } + + return root; + } + + @Override + public ConnectPoint decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + ElementId elementId; + if (json.has(ELEMENT_DEVICE)) { + elementId = DeviceId.deviceId(json.get(ELEMENT_DEVICE).asText()); + } else if (json.has(ELEMENT_HOST)) { + elementId = HostId.hostId(json.get(ELEMENT_HOST).asText()); + } else { + // invalid JSON + return null; + } + PortNumber portNumber = portNumber(json.get(PORT).asText()); + return new ConnectPoint(elementId, portNumber); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ConnectivityIntentCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ConnectivityIntentCodec.java new file mode 100644 index 00000000..9e8cd86c --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ConnectivityIntentCodec.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.codec.impl; + +import java.util.ArrayList; +import java.util.stream.IntStream; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.intent.ConnectivityIntent; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.Intent; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Connectivity intent codec. + */ +public final class ConnectivityIntentCodec extends JsonCodec { + + private static final String CONSTRAINTS = "constraints"; + private static final String SELECTOR = "selector"; + private static final String TREATMENT = "treatment"; + + @Override + public ObjectNode encode(ConnectivityIntent intent, CodecContext context) { + checkNotNull(intent, "Connectivity intent cannot be null"); + + final JsonCodec intentCodec = context.codec(Intent.class); + final ObjectNode result = intentCodec.encode(intent, context); + + if (intent.selector() != null) { + final JsonCodec selectorCodec = + context.codec(TrafficSelector.class); + result.set(SELECTOR, selectorCodec.encode(intent.selector(), context)); + } + + if (intent.treatment() != null) { + final JsonCodec treatmentCodec = + context.codec(TrafficTreatment.class); + result.set(TREATMENT, treatmentCodec.encode(intent.treatment(), context)); + } + + result.put(IntentCodec.PRIORITY, intent.priority()); + + if (intent.constraints() != null) { + final ArrayNode jsonConstraints = result.putArray(CONSTRAINTS); + + if (intent.constraints() != null) { + final JsonCodec constraintCodec = + context.codec(Constraint.class); + for (final Constraint constraint : intent.constraints()) { + final ObjectNode constraintNode = + constraintCodec.encode(constraint, context); + jsonConstraints.add(constraintNode); + } + } + } + + return result; + } + + /** + * Extracts connectivity intent specific attributes from a JSON object + * and adds them to a builder. + * + * @param json root JSON object + * @param context code context + * @param builder builder to use for storing the attributes. Constraints, + * selector and treatment are modified by this call. + */ + public static void intentAttributes(ObjectNode json, CodecContext context, + ConnectivityIntent.Builder builder) { + JsonNode constraintsJson = json.get(CONSTRAINTS); + if (constraintsJson != null) { + JsonCodec constraintsCodec = context.codec(Constraint.class); + ArrayList constraints = new ArrayList<>(constraintsJson.size()); + IntStream.range(0, constraintsJson.size()) + .forEach(i -> constraints.add( + constraintsCodec.decode(get(constraintsJson, i), + context))); + builder.constraints(constraints); + } + + ObjectNode selectorJson = get(json, SELECTOR); + if (selectorJson != null) { + JsonCodec selectorCodec = context.codec(TrafficSelector.class); + TrafficSelector selector = selectorCodec.decode(selectorJson, context); + builder.selector(selector); + } + + ObjectNode treatmentJson = get(json, TREATMENT); + if (treatmentJson != null) { + JsonCodec treatmentCodec = context.codec(TrafficTreatment.class); + TrafficTreatment treatment = treatmentCodec.decode(treatmentJson, context); + builder.treatment(treatment); + } + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ConstraintCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ConstraintCodec.java new file mode 100644 index 00000000..50738341 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ConstraintCodec.java @@ -0,0 +1,63 @@ +/* + * 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.intent.Constraint; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Constraint JSON codec. + */ +public final class ConstraintCodec extends JsonCodec { + + protected static final String MISSING_MEMBER_MESSAGE = + " member is required in Constraint"; + protected static final String TYPE = "type"; + protected static final String TYPES = "types"; + protected static final String INCLUSIVE = "inclusive"; + protected static final String KEY = "key"; + protected static final String THRESHOLD = "threshold"; + protected static final String BANDWIDTH = "bandwidth"; + protected static final String LAMBDA = "lambda"; + protected static final String LATENCY_MILLIS = "latencyMillis"; + protected static final String OBSTACLES = "obstacles"; + protected static final String WAYPOINTS = "waypoints"; + + @Override + public ObjectNode encode(Constraint constraint, CodecContext context) { + checkNotNull(constraint, "Constraint cannot be null"); + + final EncodeConstraintCodecHelper encodeCodec = + new EncodeConstraintCodecHelper(constraint, context); + + return encodeCodec.encode(); + } + + @Override + public Constraint decode(ObjectNode json, CodecContext context) { + checkNotNull(json, "JSON cannot be null"); + + final DecodeConstraintCodecHelper decodeCodec = + new DecodeConstraintCodecHelper(json); + + return decodeCodec.decode(); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ControllerNodeCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ControllerNodeCodec.java new file mode 100644 index 00000000..65d758ee --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/ControllerNodeCodec.java @@ -0,0 +1,57 @@ +/* + * 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 com.fasterxml.jackson.databind.node.ObjectNode; +import org.onlab.packet.IpAddress; +import org.onosproject.cluster.ClusterService; +import org.onosproject.cluster.ControllerNode; +import org.onosproject.cluster.DefaultControllerNode; +import org.onosproject.cluster.NodeId; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.cluster.DefaultControllerNode.DEFAULT_PORT; + +/** + * Device JSON codec. + */ +public final class ControllerNodeCodec extends JsonCodec { + + @Override + public ObjectNode encode(ControllerNode node, CodecContext context) { + checkNotNull(node, "Controller node cannot be null"); + ClusterService service = context.getService(ClusterService.class); + return context.mapper().createObjectNode() + .put("id", node.id().toString()) + .put("ip", node.ip().toString()) + .put("tcpPort", node.tcpPort()) + .put("status", service.getState(node.id()).toString()); + } + + + @Override + public ControllerNode decode(ObjectNode json, CodecContext context) { + checkNotNull(json, "JSON cannot be null"); + String ip = json.path("ip").asText(); + return new DefaultControllerNode(new NodeId(json.path("id").asText(ip)), + IpAddress.valueOf(ip), + json.path("tcpPort").asInt(DEFAULT_PORT)); + } + + +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java new file mode 100644 index 00000000..76f621f2 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java @@ -0,0 +1,78 @@ +/* + * 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.criteria.Criterion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Criterion codec. + */ +public final class CriterionCodec extends JsonCodec { + + protected static final Logger log = + LoggerFactory.getLogger(CriterionCodec.class); + + protected static final String TYPE = "type"; + protected static final String ETH_TYPE = "ethType"; + protected static final String MAC = "mac"; + protected static final String PORT = "port"; + protected static final String METADATA = "metadata"; + + protected static final String VLAN_ID = "vlanId"; + protected static final String PRIORITY = "priority"; + protected static final String IP_DSCP = "ipDscp"; + protected static final String IP_ECN = "ipEcn"; + protected static final String PROTOCOL = "protocol"; + protected static final String IP = "ip"; + protected static final String TCP_PORT = "tcpPort"; + protected static final String UDP_PORT = "udpPort"; + protected static final String SCTP_PORT = "sctpPort"; + protected static final String ICMP_TYPE = "icmpType"; + protected static final String ICMP_CODE = "icmpCode"; + protected static final String FLOW_LABEL = "flowLabel"; + protected static final String ICMPV6_TYPE = "icmpv6Type"; + protected static final String ICMPV6_CODE = "icmpv6Code"; + protected static final String TARGET_ADDRESS = "targetAddress"; + protected static final String LABEL = "label"; + protected static final String EXT_HDR_FLAGS = "exthdrFlags"; + protected static final String LAMBDA = "lambda"; + protected static final String GRID_TYPE = "gridType"; + protected static final String CHANNEL_SPACING = "channelSpacing"; + protected static final String SPACING_MULIPLIER = "spacingMultiplier"; + protected static final String SLOT_GRANULARITY = "slotGranularity"; + protected static final String OCH_SIGNAL_ID = "ochSignalId"; + protected static final String TUNNEL_ID = "tunnelId"; + + @Override + public ObjectNode encode(Criterion criterion, CodecContext context) { + EncodeCriterionCodecHelper encoder = new EncodeCriterionCodecHelper(criterion, context); + return encoder.encode(); + } + + @Override + public Criterion decode(ObjectNode json, CodecContext context) { + DecodeCriterionCodecHelper decoder = new DecodeCriterionCodecHelper(json); + return decoder.decode(); + } + + +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeConstraintCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeConstraintCodecHelper.java new file mode 100644 index 00000000..5746003c --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeConstraintCodecHelper.java @@ -0,0 +1,225 @@ +/* + * 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 java.time.Duration; +import java.util.ArrayList; +import java.util.stream.IntStream; + +import org.onlab.util.Bandwidth; +import org.onosproject.net.DeviceId; +import org.onosproject.net.IndexedLambda; +import org.onosproject.net.Link; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.constraint.AnnotationConstraint; +import org.onosproject.net.intent.constraint.AsymmetricPathConstraint; +import org.onosproject.net.intent.constraint.BandwidthConstraint; +import org.onosproject.net.intent.constraint.LambdaConstraint; +import org.onosproject.net.intent.constraint.LatencyConstraint; +import org.onosproject.net.intent.constraint.LinkTypeConstraint; +import org.onosproject.net.intent.constraint.ObstacleConstraint; +import org.onosproject.net.intent.constraint.WaypointConstraint; +import org.onosproject.net.resource.link.BandwidthResource; +import org.onosproject.net.resource.link.LambdaResource; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static org.onlab.util.Tools.nullIsIllegal; + +/** + * Constraint JSON decoder. + */ +public final class DecodeConstraintCodecHelper { + private final ObjectNode json; + + /** + * Constructs a constraint decoder. + * + * @param json object node to decode + */ + public DecodeConstraintCodecHelper(ObjectNode json) { + this.json = json; + } + + /** + * Decodes a link type constraint. + * + * @return link type constraint object. + */ + private Constraint decodeLinkTypeConstraint() { + boolean inclusive = nullIsIllegal(json.get(ConstraintCodec.INCLUSIVE), + ConstraintCodec.INCLUSIVE + ConstraintCodec.MISSING_MEMBER_MESSAGE).asBoolean(); + + JsonNode types = nullIsIllegal(json.get(ConstraintCodec.TYPES), + ConstraintCodec.TYPES + ConstraintCodec.MISSING_MEMBER_MESSAGE); + if (types.size() < 1) { + throw new IllegalArgumentException( + "types array in link constraint must have at least one value"); + } + + ArrayList typesEntries = new ArrayList<>(types.size()); + IntStream.range(0, types.size()) + .forEach(index -> + typesEntries.add(Link.Type.valueOf(types.get(index).asText()))); + + return new LinkTypeConstraint(inclusive, + typesEntries.toArray(new Link.Type[types.size()])); + } + + /** + * Decodes an annotation constraint. + * + * @return annotation constraint object. + */ + private Constraint decodeAnnotationConstraint() { + String key = nullIsIllegal(json.get(ConstraintCodec.KEY), + ConstraintCodec.KEY + ConstraintCodec.MISSING_MEMBER_MESSAGE) + .asText(); + double threshold = nullIsIllegal(json.get(ConstraintCodec.THRESHOLD), + ConstraintCodec.THRESHOLD + ConstraintCodec.MISSING_MEMBER_MESSAGE) + .asDouble(); + + return new AnnotationConstraint(key, threshold); + } + + /** + * Decodes a lambda constraint. + * + * @return lambda constraint object. + */ + private Constraint decodeLambdaConstraint() { + long lambda = nullIsIllegal(json.get(ConstraintCodec.LAMBDA), + ConstraintCodec.LAMBDA + ConstraintCodec.MISSING_MEMBER_MESSAGE) + .asLong(); + + return new LambdaConstraint(LambdaResource.valueOf(new IndexedLambda(lambda))); + } + + /** + * Decodes a latency constraint. + * + * @return latency constraint object. + */ + private Constraint decodeLatencyConstraint() { + long latencyMillis = nullIsIllegal(json.get(ConstraintCodec.LATENCY_MILLIS), + ConstraintCodec.LATENCY_MILLIS + ConstraintCodec.MISSING_MEMBER_MESSAGE) + .asLong(); + + return new LatencyConstraint(Duration.ofMillis(latencyMillis)); + } + + /** + * Decodes an obstacle constraint. + * + * @return obstacle constraint object. + */ + private Constraint decodeObstacleConstraint() { + JsonNode obstacles = nullIsIllegal(json.get(ConstraintCodec.OBSTACLES), + ConstraintCodec.OBSTACLES + ConstraintCodec.MISSING_MEMBER_MESSAGE); + if (obstacles.size() < 1) { + throw new IllegalArgumentException( + "obstacles array in obstacles constraint must have at least one value"); + } + + ArrayList obstacleEntries = new ArrayList<>(obstacles.size()); + IntStream.range(0, obstacles.size()) + .forEach(index -> + obstacleEntries.add(DeviceId.deviceId(obstacles.get(index).asText()))); + + return new ObstacleConstraint( + obstacleEntries.toArray(new DeviceId[obstacles.size()])); + } + + /** + * Decodes a waypoint constraint. + * + * @return waypoint constraint object. + */ + private Constraint decodeWaypointConstraint() { + JsonNode waypoints = nullIsIllegal(json.get(ConstraintCodec.WAYPOINTS), + ConstraintCodec.WAYPOINTS + ConstraintCodec.MISSING_MEMBER_MESSAGE); + if (waypoints.size() < 1) { + throw new IllegalArgumentException( + "obstacles array in obstacles constraint must have at least one value"); + } + + ArrayList waypointEntries = new ArrayList<>(waypoints.size()); + IntStream.range(0, waypoints.size()) + .forEach(index -> + waypointEntries.add(DeviceId.deviceId(waypoints.get(index).asText()))); + + return new WaypointConstraint( + waypointEntries.toArray(new DeviceId[waypoints.size()])); + } + + /** + * Decodes an asymmetric path constraint. + * + * @return asymmetric path constraint object. + */ + private Constraint decodeAsymmetricPathConstraint() { + return new AsymmetricPathConstraint(); + } + + /** + * Decodes a bandwidth constraint. + * + * @return bandwidth constraint object. + */ + private Constraint decodeBandwidthConstraint() { + double bandwidth = nullIsIllegal(json.get(ConstraintCodec.BANDWIDTH), + ConstraintCodec.BANDWIDTH + ConstraintCodec.MISSING_MEMBER_MESSAGE) + .asDouble(); + + return new BandwidthConstraint(new BandwidthResource(Bandwidth.bps(bandwidth))); + } + + /** + * Decodes the given constraint. + * + * @return constraint object. + */ + public Constraint decode() { + final String type = nullIsIllegal(json.get(ConstraintCodec.TYPE), + ConstraintCodec.TYPE + ConstraintCodec.MISSING_MEMBER_MESSAGE) + .asText(); + + if (type.equals(BandwidthConstraint.class.getSimpleName())) { + return decodeBandwidthConstraint(); + } else if (type.equals(LambdaConstraint.class.getSimpleName())) { + return decodeLambdaConstraint(); + } else if (type.equals(LinkTypeConstraint.class.getSimpleName())) { + return decodeLinkTypeConstraint(); + } else if (type.equals(AnnotationConstraint.class.getSimpleName())) { + return decodeAnnotationConstraint(); + } else if (type.equals(LatencyConstraint.class.getSimpleName())) { + return decodeLatencyConstraint(); + } else if (type.equals(ObstacleConstraint.class.getSimpleName())) { + return decodeObstacleConstraint(); + } else if (type.equals(WaypointConstraint.class.getSimpleName())) { + return decodeWaypointConstraint(); + } else if (type.equals(AsymmetricPathConstraint.class.getSimpleName())) { + return decodeAsymmetricPathConstraint(); + } else if (type.equals(LinkTypeConstraint.class.getSimpleName())) { + return decodeLinkTypeConstraint(); + } else if (type.equals(AnnotationConstraint.class.getSimpleName())) { + return decodeAnnotationConstraint(); + } + throw new IllegalArgumentException("Instruction type " + + type + " is not supported"); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java new file mode 100644 index 00000000..4e0f2bd9 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java @@ -0,0 +1,449 @@ +/* + * 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 java.util.HashMap; +import java.util.Map; + +import org.onlab.packet.Ip6Address; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.TpPort; +import org.onlab.packet.VlanId; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.GridType; +import org.onosproject.net.Lambda; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.criteria.Criteria; +import org.onosproject.net.flow.criteria.Criterion; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static org.onlab.util.Tools.nullIsIllegal; + +/** + * Decode portion of the criterion codec. + */ +public final class DecodeCriterionCodecHelper { + + private final ObjectNode json; + + protected static final String MISSING_MEMBER_MESSAGE = + " member is required in Criterion"; + + private interface CriterionDecoder { + Criterion decodeCriterion(ObjectNode json); + } + private final Map decoderMap; + + /** + * Creates a decode criterion codec object. + * Initializes the lookup map for criterion subclass decoders. + * + * @param json JSON object to decode + */ + public DecodeCriterionCodecHelper(ObjectNode json) { + this.json = json; + decoderMap = new HashMap<>(); + + decoderMap.put(Criterion.Type.IN_PORT.name(), new InPortDecoder()); + decoderMap.put(Criterion.Type.IN_PHY_PORT.name(), new InPhyPortDecoder()); + decoderMap.put(Criterion.Type.METADATA.name(), new MetadataDecoder()); + decoderMap.put(Criterion.Type.ETH_DST.name(), new EthDstDecoder()); + decoderMap.put(Criterion.Type.ETH_SRC.name(), new EthSrcDecoder()); + decoderMap.put(Criterion.Type.ETH_TYPE.name(), new EthTypeDecoder()); + decoderMap.put(Criterion.Type.VLAN_VID.name(), new VlanVidDecoder()); + decoderMap.put(Criterion.Type.VLAN_PCP.name(), new VlanPcpDecoder()); + decoderMap.put(Criterion.Type.IP_DSCP.name(), new IpDscpDecoder()); + decoderMap.put(Criterion.Type.IP_ECN.name(), new IpEcnDecoder()); + decoderMap.put(Criterion.Type.IP_PROTO.name(), new IpProtoDecoder()); + decoderMap.put(Criterion.Type.IPV4_SRC.name(), new IpV4SrcDecoder()); + decoderMap.put(Criterion.Type.IPV4_DST.name(), new IpV4DstDecoder()); + decoderMap.put(Criterion.Type.TCP_SRC.name(), new TcpSrcDecoder()); + decoderMap.put(Criterion.Type.TCP_DST.name(), new TcpDstDecoder()); + decoderMap.put(Criterion.Type.UDP_SRC.name(), new UdpSrcDecoder()); + decoderMap.put(Criterion.Type.UDP_DST.name(), new UdpDstDecoder()); + decoderMap.put(Criterion.Type.SCTP_SRC.name(), new SctpSrcDecoder()); + decoderMap.put(Criterion.Type.SCTP_DST.name(), new SctpDstDecoder()); + decoderMap.put(Criterion.Type.ICMPV4_TYPE.name(), new IcmpV4TypeDecoder()); + decoderMap.put(Criterion.Type.ICMPV4_CODE.name(), new IcmpV4CodeDecoder()); + decoderMap.put(Criterion.Type.IPV6_SRC.name(), new IpV6SrcDecoder()); + decoderMap.put(Criterion.Type.IPV6_DST.name(), new IpV6DstDecoder()); + decoderMap.put(Criterion.Type.IPV6_FLABEL.name(), new IpV6FLabelDecoder()); + decoderMap.put(Criterion.Type.ICMPV6_TYPE.name(), new IcmpV6TypeDecoder()); + decoderMap.put(Criterion.Type.ICMPV6_CODE.name(), new IcmpV6CodeDecoder()); + decoderMap.put(Criterion.Type.IPV6_ND_TARGET.name(), new V6NDTargetDecoder()); + decoderMap.put(Criterion.Type.IPV6_ND_SLL.name(), new V6NDSllDecoder()); + decoderMap.put(Criterion.Type.IPV6_ND_TLL.name(), new V6NDTllDecoder()); + decoderMap.put(Criterion.Type.MPLS_LABEL.name(), new MplsLabelDecoder()); + decoderMap.put(Criterion.Type.IPV6_EXTHDR.name(), new IpV6ExthdrDecoder()); + decoderMap.put(Criterion.Type.OCH_SIGID.name(), new OchSigIdDecoder()); + decoderMap.put(Criterion.Type.OCH_SIGTYPE.name(), new OchSigTypeDecoder()); + decoderMap.put(Criterion.Type.TUNNEL_ID.name(), new TunnelIdDecoder()); + } + + private class EthTypeDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + int ethType = nullIsIllegal(json.get(CriterionCodec.ETH_TYPE), + CriterionCodec.ETH_TYPE + MISSING_MEMBER_MESSAGE).asInt(); + return Criteria.matchEthType(ethType); + } + } + + private class EthDstDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + MacAddress mac = MacAddress.valueOf(nullIsIllegal(json.get(CriterionCodec.MAC), + CriterionCodec.MAC + MISSING_MEMBER_MESSAGE).asText()); + + return Criteria.matchEthDst(mac); + } + } + + private class EthSrcDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + MacAddress mac = MacAddress.valueOf(nullIsIllegal(json.get(CriterionCodec.MAC), + CriterionCodec.MAC + MISSING_MEMBER_MESSAGE).asText()); + + return Criteria.matchEthSrc(mac); + } + } + + private class InPortDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + PortNumber port = PortNumber.portNumber(nullIsIllegal(json.get(CriterionCodec.PORT), + CriterionCodec.PORT + MISSING_MEMBER_MESSAGE).asLong()); + + return Criteria.matchInPort(port); + } + } + + private class InPhyPortDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + PortNumber port = PortNumber.portNumber(nullIsIllegal(json.get(CriterionCodec.PORT), + CriterionCodec.PORT + MISSING_MEMBER_MESSAGE).asLong()); + + return Criteria.matchInPhyPort(port); + } + } + + private class MetadataDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + long metadata = nullIsIllegal(json.get(CriterionCodec.METADATA), + CriterionCodec.METADATA + MISSING_MEMBER_MESSAGE).asLong(); + + return Criteria.matchMetadata(metadata); + } + } + + private class VlanVidDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + short vlanId = (short) nullIsIllegal(json.get(CriterionCodec.VLAN_ID), + CriterionCodec.VLAN_ID + MISSING_MEMBER_MESSAGE).asInt(); + + return Criteria.matchVlanId(VlanId.vlanId(vlanId)); + } + } + + private class VlanPcpDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + byte priority = (byte) nullIsIllegal(json.get(CriterionCodec.PRIORITY), + CriterionCodec.VLAN_ID + MISSING_MEMBER_MESSAGE).asInt(); + + return Criteria.matchVlanPcp(priority); + } + } + + private class IpDscpDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + byte ipDscp = (byte) nullIsIllegal(json.get(CriterionCodec.IP_DSCP), + CriterionCodec.IP_DSCP + MISSING_MEMBER_MESSAGE).asInt(); + return Criteria.matchIPDscp(ipDscp); + } + } + + private class IpEcnDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + byte ipEcn = (byte) nullIsIllegal(json.get(CriterionCodec.IP_ECN), + CriterionCodec.IP_ECN + MISSING_MEMBER_MESSAGE).asInt(); + return Criteria.matchIPEcn(ipEcn); + } + } + + private class IpProtoDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + short proto = (short) nullIsIllegal(json.get(CriterionCodec.PROTOCOL), + CriterionCodec.PROTOCOL + MISSING_MEMBER_MESSAGE).asInt(); + return Criteria.matchIPProtocol(proto); + } + } + + private class IpV4SrcDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + String ip = nullIsIllegal(json.get(CriterionCodec.IP), + CriterionCodec.IP + MISSING_MEMBER_MESSAGE).asText(); + return Criteria.matchIPSrc(IpPrefix.valueOf(ip)); + } + } + + private class IpV4DstDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + String ip = nullIsIllegal(json.get(CriterionCodec.IP), + CriterionCodec.IP + MISSING_MEMBER_MESSAGE).asText(); + return Criteria.matchIPDst(IpPrefix.valueOf(ip)); + } + } + + private class IpV6SrcDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + String ip = nullIsIllegal(json.get(CriterionCodec.IP), + CriterionCodec.IP + MISSING_MEMBER_MESSAGE).asText(); + return Criteria.matchIPv6Src(IpPrefix.valueOf(ip)); + } + } + + private class IpV6DstDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + String ip = nullIsIllegal(json.get(CriterionCodec.IP), + CriterionCodec.IP + MISSING_MEMBER_MESSAGE).asText(); + return Criteria.matchIPv6Dst(IpPrefix.valueOf(ip)); + } + } + + private class TcpSrcDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + TpPort tcpPort = TpPort.tpPort(nullIsIllegal(json.get(CriterionCodec.TCP_PORT), + CriterionCodec.TCP_PORT + MISSING_MEMBER_MESSAGE).asInt()); + return Criteria.matchTcpSrc(tcpPort); + } + } + + private class TcpDstDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + TpPort tcpPort = TpPort.tpPort(nullIsIllegal(json.get(CriterionCodec.TCP_PORT), + CriterionCodec.TCP_PORT + MISSING_MEMBER_MESSAGE).asInt()); + return Criteria.matchTcpDst(tcpPort); + } + } + + private class UdpSrcDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + TpPort udpPort = TpPort.tpPort(nullIsIllegal(json.get(CriterionCodec.UDP_PORT), + CriterionCodec.UDP_PORT + MISSING_MEMBER_MESSAGE).asInt()); + return Criteria.matchUdpSrc(udpPort); + } + } + + private class UdpDstDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + TpPort udpPort = TpPort.tpPort(nullIsIllegal(json.get(CriterionCodec.UDP_PORT), + CriterionCodec.UDP_PORT + MISSING_MEMBER_MESSAGE).asInt()); + return Criteria.matchUdpDst(udpPort); + } + } + + private class SctpSrcDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + TpPort sctpPort = TpPort.tpPort(nullIsIllegal(json.get(CriterionCodec.SCTP_PORT), + CriterionCodec.SCTP_PORT + MISSING_MEMBER_MESSAGE).asInt()); + return Criteria.matchSctpSrc(sctpPort); + } + } + + private class SctpDstDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + TpPort sctpPort = TpPort.tpPort(nullIsIllegal(json.get(CriterionCodec.SCTP_PORT), + CriterionCodec.SCTP_PORT + MISSING_MEMBER_MESSAGE).asInt()); + return Criteria.matchSctpDst(sctpPort); + } + } + + private class IcmpV4TypeDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + short type = (short) nullIsIllegal(json.get(CriterionCodec.ICMP_TYPE), + CriterionCodec.ICMP_TYPE + MISSING_MEMBER_MESSAGE).asInt(); + return Criteria.matchIcmpType(type); + } + } + + private class IcmpV4CodeDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + short code = (short) nullIsIllegal(json.get(CriterionCodec.ICMP_CODE), + CriterionCodec.ICMP_CODE + MISSING_MEMBER_MESSAGE).asInt(); + return Criteria.matchIcmpCode(code); + } + } + + private class IpV6FLabelDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + int flowLabel = nullIsIllegal(json.get(CriterionCodec.FLOW_LABEL), + CriterionCodec.FLOW_LABEL + MISSING_MEMBER_MESSAGE).asInt(); + return Criteria.matchIPv6FlowLabel(flowLabel); + } + } + + private class IcmpV6TypeDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + short type = (short) nullIsIllegal(json.get(CriterionCodec.ICMPV6_TYPE), + CriterionCodec.ICMPV6_TYPE + MISSING_MEMBER_MESSAGE).asInt(); + return Criteria.matchIcmpv6Type(type); + } + } + + private class IcmpV6CodeDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + short code = (short) nullIsIllegal(json.get(CriterionCodec.ICMPV6_CODE), + CriterionCodec.ICMPV6_CODE + MISSING_MEMBER_MESSAGE).asInt(); + return Criteria.matchIcmpv6Code(code); + } + } + + private class V6NDTargetDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + Ip6Address target = Ip6Address.valueOf(nullIsIllegal(json.get(CriterionCodec.TARGET_ADDRESS), + CriterionCodec.TARGET_ADDRESS + MISSING_MEMBER_MESSAGE).asText()); + return Criteria.matchIPv6NDTargetAddress(target); + } + } + + private class V6NDSllDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + MacAddress mac = MacAddress.valueOf(nullIsIllegal(json.get(CriterionCodec.MAC), + CriterionCodec.MAC + MISSING_MEMBER_MESSAGE).asText()); + return Criteria.matchIPv6NDSourceLinkLayerAddress(mac); + } + } + + private class V6NDTllDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + MacAddress mac = MacAddress.valueOf(nullIsIllegal(json.get(CriterionCodec.MAC), + CriterionCodec.MAC + MISSING_MEMBER_MESSAGE).asText()); + return Criteria.matchIPv6NDTargetLinkLayerAddress(mac); + } + } + + private class MplsLabelDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + int label = nullIsIllegal(json.get(CriterionCodec.LABEL), + CriterionCodec.LABEL + MISSING_MEMBER_MESSAGE).asInt(); + return Criteria.matchMplsLabel(MplsLabel.mplsLabel(label)); + } + } + + private class IpV6ExthdrDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + int exthdrFlags = nullIsIllegal(json.get(CriterionCodec.EXT_HDR_FLAGS), + CriterionCodec.EXT_HDR_FLAGS + MISSING_MEMBER_MESSAGE).asInt(); + return Criteria.matchIPv6ExthdrFlags(exthdrFlags); + } + } + + private class OchSigIdDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + if (json.get(CriterionCodec.LAMBDA) != null) { + Lambda lambda = Lambda.indexedLambda(nullIsIllegal(json.get(CriterionCodec.LAMBDA), + CriterionCodec.LAMBDA + MISSING_MEMBER_MESSAGE).asInt()); + return Criteria.matchLambda(lambda); + } else { + JsonNode ochSignalId = nullIsIllegal(json.get(CriterionCodec.OCH_SIGNAL_ID), + CriterionCodec.GRID_TYPE + MISSING_MEMBER_MESSAGE); + GridType gridType = + GridType.valueOf( + nullIsIllegal(ochSignalId.get(CriterionCodec.GRID_TYPE), + CriterionCodec.GRID_TYPE + MISSING_MEMBER_MESSAGE).asText()); + ChannelSpacing channelSpacing = + ChannelSpacing.valueOf( + nullIsIllegal(ochSignalId.get(CriterionCodec.CHANNEL_SPACING), + CriterionCodec.CHANNEL_SPACING + MISSING_MEMBER_MESSAGE).asText()); + int spacingMultiplier = nullIsIllegal(ochSignalId.get(CriterionCodec.SPACING_MULIPLIER), + CriterionCodec.SPACING_MULIPLIER + MISSING_MEMBER_MESSAGE).asInt(); + int slotGranularity = nullIsIllegal(ochSignalId.get(CriterionCodec.SLOT_GRANULARITY), + CriterionCodec.SLOT_GRANULARITY + MISSING_MEMBER_MESSAGE).asInt(); + return Criteria.matchLambda( + Lambda.ochSignal(gridType, channelSpacing, + spacingMultiplier, slotGranularity)); + } + } + } + + private class OchSigTypeDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + return null; + } + } + + private class TunnelIdDecoder implements CriterionDecoder { + @Override + public Criterion decodeCriterion(ObjectNode json) { + long tunnelId = nullIsIllegal(json.get(CriterionCodec.TUNNEL_ID), + CriterionCodec.TUNNEL_ID + MISSING_MEMBER_MESSAGE).asLong(); + return Criteria.matchTunnelId(tunnelId); + } + } + + /** + * Decodes the JSON into a criterion object. + * + * @return Criterion object + * @throws IllegalArgumentException if the JSON is invalid + */ + public Criterion decode() { + String type = json.get(CriterionCodec.TYPE).asText(); + + CriterionDecoder decoder = decoderMap.get(type); + if (decoder != null) { + return decoder.decodeCriterion(json); + } + + throw new IllegalArgumentException("Type " + type + " is unknown"); + } + + +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java new file mode 100644 index 00000000..6a97a076 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java @@ -0,0 +1,235 @@ +/* + * 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.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.TpPort; +import org.onlab.packet.VlanId; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.GridType; +import org.onosproject.net.Lambda; +import org.onosproject.net.OchSignal; +import org.onosproject.net.PortNumber; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.net.flow.instructions.Instruction; +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.flow.instructions.L4ModificationInstruction; + +import static org.onlab.util.Tools.nullIsIllegal; + +/** + * Decoding portion of the instruction codec. + */ +public final class DecodeInstructionCodecHelper { + private final ObjectNode json; + + /** + * Creates a decode instruction codec object. + * + * @param json JSON object to decode + */ + public DecodeInstructionCodecHelper(ObjectNode json) { + this.json = json; + } + + /** + * Decodes a Layer 2 instruction. + * + * @return instruction object decoded from the JSON + * @throws IllegalArgumentException if the JSON is invalid + */ + private Instruction decodeL2() { + String subType = json.get(InstructionCodec.SUBTYPE).asText(); + + if (subType.equals(L2ModificationInstruction.L2SubType.ETH_SRC.name())) { + String mac = nullIsIllegal(json.get(InstructionCodec.MAC), + InstructionCodec.MAC + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); + return Instructions.modL2Src(MacAddress.valueOf(mac)); + } else if (subType.equals(L2ModificationInstruction.L2SubType.ETH_DST.name())) { + String mac = nullIsIllegal(json.get(InstructionCodec.MAC), + InstructionCodec.MAC + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); + return Instructions.modL2Dst(MacAddress.valueOf(mac)); + } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_ID.name())) { + short vlanId = (short) nullIsIllegal(json.get(InstructionCodec.VLAN_ID), + InstructionCodec.VLAN_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); + return Instructions.modVlanId(VlanId.vlanId(vlanId)); + } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PCP.name())) { + byte vlanPcp = (byte) nullIsIllegal(json.get(InstructionCodec.VLAN_PCP), + InstructionCodec.VLAN_PCP + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); + return Instructions.modVlanPcp(vlanPcp); + } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_LABEL.name())) { + int label = nullIsIllegal(json.get(InstructionCodec.MPLS_LABEL), + InstructionCodec.MPLS_LABEL + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); + return Instructions.modMplsLabel(MplsLabel.mplsLabel(label)); + } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_PUSH.name())) { + return Instructions.pushMpls(); + } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_POP.name())) { + return Instructions.popMpls(); + } else if (subType.equals(L2ModificationInstruction.L2SubType.DEC_MPLS_TTL.name())) { + return Instructions.decMplsTtl(); + } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_POP.name())) { + return Instructions.popVlan(); + } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PUSH.name())) { + return Instructions.pushVlan(); + } else if (subType.equals(L2ModificationInstruction.L2SubType.TUNNEL_ID.name())) { + long tunnelId = nullIsIllegal(json.get(InstructionCodec.TUNNEL_ID), + InstructionCodec.TUNNEL_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong(); + return Instructions.modTunnelId(tunnelId); + } + throw new IllegalArgumentException("L2 Instruction subtype " + + subType + " is not supported"); + } + + /** + * Decodes a Layer 3 instruction. + * + * @return instruction object decoded from the JSON + * @throws IllegalArgumentException if the JSON is invalid + */ + private Instruction decodeL3() { + String subType = json.get(InstructionCodec.SUBTYPE).asText(); + + if (subType.equals(L3ModificationInstruction.L3SubType.IPV4_SRC.name())) { + IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), + InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); + return Instructions.modL3Src(ip); + } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV4_DST.name())) { + IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), + InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); + return Instructions.modL3Dst(ip); + } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_SRC.name())) { + IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), + InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); + return Instructions.modL3IPv6Src(ip); + } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_DST.name())) { + IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), + InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); + return Instructions.modL3IPv6Dst(ip); + } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_FLABEL.name())) { + int flowLabel = nullIsIllegal(json.get(InstructionCodec.FLOW_LABEL), + InstructionCodec.FLOW_LABEL + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); + return Instructions.modL3IPv6FlowLabel(flowLabel); + } + throw new IllegalArgumentException("L3 Instruction subtype " + + subType + " is not supported"); + } + + /** + * Decodes a Layer 0 instruction. + * + * @return instruction object decoded from the JSON + * @throws IllegalArgumentException if the JSON is invalid + */ + private Instruction decodeL0() { + String subType = json.get(InstructionCodec.SUBTYPE).asText(); + + + if (subType.equals(L0ModificationInstruction.L0SubType.LAMBDA.name())) { + int lambda = nullIsIllegal(json.get(InstructionCodec.LAMBDA), + InstructionCodec.LAMBDA + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); + return Instructions.modL0Lambda(Lambda.indexedLambda(lambda)); + } else if (subType.equals(L0ModificationInstruction.L0SubType.OCH.name())) { + String gridTypeString = nullIsIllegal(json.get(InstructionCodec.GRID_TYPE), + InstructionCodec.GRID_TYPE + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); + GridType gridType = GridType.valueOf(gridTypeString); + if (gridType == null) { + throw new IllegalArgumentException("Unknown grid type " + + gridTypeString); + } + String channelSpacingString = nullIsIllegal(json.get(InstructionCodec.CHANNEL_SPACING), + InstructionCodec.CHANNEL_SPACING + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); + ChannelSpacing channelSpacing = ChannelSpacing.valueOf(channelSpacingString); + if (channelSpacing == null) { + throw new IllegalArgumentException("Unknown channel spacing " + + channelSpacingString); + } + int spacingMultiplier = nullIsIllegal(json.get(InstructionCodec.SPACING_MULTIPLIER), + InstructionCodec.SPACING_MULTIPLIER + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); + int slotGranularity = nullIsIllegal(json.get(InstructionCodec.SLOT_GRANULARITY), + InstructionCodec.SLOT_GRANULARITY + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); + return Instructions.modL0Lambda(new OchSignal(gridType, channelSpacing, + spacingMultiplier, slotGranularity)); + } + throw new IllegalArgumentException("L0 Instruction subtype " + + subType + " is not supported"); + } + + /** + * Decodes a Layer 4 instruction. + * + * @return instruction object decoded from the JSON + * @throws IllegalArgumentException if the JSON is invalid + */ + private Instruction decodeL4() { + String subType = json.get(InstructionCodec.SUBTYPE).asText(); + + if (subType.equals(L4ModificationInstruction.L4SubType.TCP_DST.name())) { + TpPort tcpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.TCP_PORT), + InstructionCodec.TCP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt()); + return Instructions.modTcpDst(tcpPort); + } else if (subType.equals(L4ModificationInstruction.L4SubType.TCP_SRC.name())) { + TpPort tcpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.TCP_PORT), + InstructionCodec.TCP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt()); + return Instructions.modTcpSrc(tcpPort); + } else if (subType.equals(L4ModificationInstruction.L4SubType.UDP_DST.name())) { + TpPort udpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.UDP_PORT), + InstructionCodec.UDP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt()); + return Instructions.modUdpDst(udpPort); + } else if (subType.equals(L4ModificationInstruction.L4SubType.UDP_SRC.name())) { + TpPort udpPort = TpPort.tpPort(nullIsIllegal(json.get(InstructionCodec.UDP_PORT), + InstructionCodec.UDP_PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt()); + return Instructions.modUdpSrc(udpPort); + } + throw new IllegalArgumentException("L4 Instruction subtype " + + subType + " is not supported"); + } + + /** + * Decodes the JSON into an instruction object. + * + * @return Criterion object + * @throws IllegalArgumentException if the JSON is invalid + */ + public Instruction decode() { + String type = json.get(InstructionCodec.TYPE).asText(); + + if (type.equals(Instruction.Type.OUTPUT.name())) { + PortNumber portNumber = + PortNumber.portNumber(nullIsIllegal(json.get(InstructionCodec.PORT), + InstructionCodec.PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong()); + return Instructions.createOutput(portNumber); + } else if (type.equals(Instruction.Type.DROP.name())) { + return Instructions.createDrop(); + } else if (type.equals(Instruction.Type.L0MODIFICATION.name())) { + return decodeL0(); + } else if (type.equals(Instruction.Type.L2MODIFICATION.name())) { + return decodeL2(); + } else if (type.equals(Instruction.Type.L3MODIFICATION.name())) { + return decodeL3(); + } else if (type.equals(Instruction.Type.L4MODIFICATION.name())) { + return decodeL4(); + } + throw new IllegalArgumentException("Instruction type " + + type + " is not supported"); + } + +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DeviceCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DeviceCodec.java new file mode 100644 index 00000000..f1a4f786 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DeviceCodec.java @@ -0,0 +1,93 @@ +/* + * Copyright 2014-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 com.fasterxml.jackson.databind.node.ObjectNode; + +import org.onlab.packet.ChassisId; +import org.onosproject.codec.CodecContext; +import org.onosproject.net.Annotations; +import org.onosproject.net.DefaultDevice; +import org.onosproject.net.Device; +import org.onosproject.net.Device.Type; +import org.onosproject.net.DeviceId; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.provider.ProviderId; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.DeviceId.deviceId; + +/** + * Device JSON codec. + */ +public final class DeviceCodec extends AnnotatedCodec { + + // JSON fieldNames + private static final String ID = "id"; + private static final String TYPE = "type"; + private static final String MFR = "mfr"; + private static final String HW = "hw"; + private static final String SW = "sw"; + private static final String SERIAL = "serial"; + private static final String CHASSIS_ID = "chassisId"; + + + @Override + public ObjectNode encode(Device device, CodecContext context) { + checkNotNull(device, "Device cannot be null"); + DeviceService service = context.getService(DeviceService.class); + ObjectNode result = context.mapper().createObjectNode() + .put(ID, device.id().toString()) + .put(TYPE, device.type().name()) + .put("available", service.isAvailable(device.id())) + .put("role", service.getRole(device.id()).toString()) + .put(MFR, device.manufacturer()) + .put(HW, device.hwVersion()) + .put(SW, device.swVersion()) + .put(SERIAL, device.serialNumber()) + .put(CHASSIS_ID, device.chassisId().toString()); + return annotate(result, device, context); + } + + + /** + * {@inheritDoc} + * + * Note: ProviderId is not part of JSON representation. + * Returned object will have random ProviderId set. + */ + @Override + public Device decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + DeviceId id = deviceId(json.get(ID).asText()); + // TODO: add providerId to JSON if we need to recover them. + ProviderId pid = new ProviderId(id.uri().getScheme(), "DeviceCodec"); + + Type type = Type.valueOf(json.get(TYPE).asText()); + String mfr = json.get(MFR).asText(); + String hw = json.get(HW).asText(); + String sw = json.get(SW).asText(); + String serial = json.get(SERIAL).asText(); + ChassisId chassisId = new ChassisId(json.get(CHASSIS_ID).asText()); + Annotations annotations = extractAnnotations(json, context); + + return new DefaultDevice(pid, id, type, mfr, hw, sw, serial, + chassisId, annotations); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DriverCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DriverCodec.java new file mode 100644 index 00000000..4935d992 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/DriverCodec.java @@ -0,0 +1,78 @@ +/* + * 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.driver.Driver; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * JSON codec for the Driver class. + */ +public final class DriverCodec extends JsonCodec { + private static final String PARENT = "parent"; + private static final String NAME = "name"; + private static final String MANUFACTURER = "manufacturer"; + private static final String HW_VERSION = "hwVersion"; + private static final String SW_VERSION = "swVersion"; + private static final String BEHAVIOURS = "behaviours"; + private static final String BEHAVIORS_NAME = "name"; + private static final String BEHAVIORS_IMPLEMENTATION_NAME = "implementationName"; + private static final String PROPERTIES = "properties"; + + @Override + public ObjectNode encode(Driver driver, CodecContext context) { + checkNotNull(driver, "Driver cannot be null"); + + ObjectNode result = context.mapper().createObjectNode() + .put(NAME, driver.name()) + .put(MANUFACTURER, driver.manufacturer()) + .put(HW_VERSION, driver.hwVersion()) + .put(SW_VERSION, driver.swVersion()); + + if (driver.parent() != null) { + result.put(PARENT, driver.parent().name()); + } + + ArrayNode behaviours = context.mapper().createArrayNode(); + driver.behaviours().forEach(behaviour -> { + ObjectNode entry = context.mapper().createObjectNode() + .put(BEHAVIORS_NAME, behaviour.getCanonicalName()) + .put(BEHAVIORS_IMPLEMENTATION_NAME, + driver.implementation(behaviour).getCanonicalName()); + + behaviours.add(entry); + }); + result.set(BEHAVIOURS, behaviours); + + ArrayNode properties = context.mapper().createArrayNode(); + driver.properties().forEach((name, value) -> { + ObjectNode entry = context.mapper().createObjectNode() + .put("name", name) + .put("value", value); + + properties.add(entry); + }); + result.set(PROPERTIES, properties); + + return result; + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeConstraintCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeConstraintCodecHelper.java new file mode 100644 index 00000000..61f4dbf4 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeConstraintCodecHelper.java @@ -0,0 +1,201 @@ +/* + * 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.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.constraint.AnnotationConstraint; +import org.onosproject.net.intent.constraint.BandwidthConstraint; +import org.onosproject.net.intent.constraint.LambdaConstraint; +import org.onosproject.net.intent.constraint.LatencyConstraint; +import org.onosproject.net.intent.constraint.LinkTypeConstraint; +import org.onosproject.net.intent.constraint.ObstacleConstraint; +import org.onosproject.net.intent.constraint.WaypointConstraint; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Implementation of encoder for constraint JSON codec. + */ +public final class EncodeConstraintCodecHelper { + + private final Constraint constraint; + private final CodecContext context; + + /** + * Constructs a constraint encoder. + * + * @param constraint constraint to encode + * @param context to use for look ups + */ + public EncodeConstraintCodecHelper(Constraint constraint, CodecContext context) { + this.constraint = constraint; + this.context = context; + } + + /** + * Encodes a latency constraint. + * + * @return JSON ObjectNode representing the constraint + */ + private ObjectNode encodeLatencyConstraint() { + checkNotNull(constraint, "Duration constraint cannot be null"); + final LatencyConstraint latencyConstraint = + (LatencyConstraint) constraint; + return context.mapper().createObjectNode() + .put("latencyMillis", latencyConstraint.latency().toMillis()); + } + + /** + * Encodes an obstacle constraint. + * + * @return JSON ObjectNode representing the constraint + */ + private ObjectNode encodeObstacleConstraint() { + checkNotNull(constraint, "Obstacle constraint cannot be null"); + final ObstacleConstraint obstacleConstraint = + (ObstacleConstraint) constraint; + + final ObjectNode result = context.mapper().createObjectNode(); + final ArrayNode jsonObstacles = result.putArray("obstacles"); + + for (DeviceId did : obstacleConstraint.obstacles()) { + jsonObstacles.add(did.toString()); + } + + return result; + } + + /** + * Encodes a waypoint constraint. + * + * @return JSON ObjectNode representing the constraint + */ + private ObjectNode encodeWaypointConstraint() { + checkNotNull(constraint, "Waypoint constraint cannot be null"); + final WaypointConstraint waypointConstraint = + (WaypointConstraint) constraint; + + final ObjectNode result = context.mapper().createObjectNode(); + final ArrayNode jsonWaypoints = result.putArray("waypoints"); + + for (DeviceId did : waypointConstraint.waypoints()) { + jsonWaypoints.add(did.toString()); + } + + return result; + } + + /** + * Encodes a annotation constraint. + * + * @return JSON ObjectNode representing the constraint + */ + private ObjectNode encodeAnnotationConstraint() { + checkNotNull(constraint, "Annotation constraint cannot be null"); + final AnnotationConstraint annotationConstraint = + (AnnotationConstraint) constraint; + return context.mapper().createObjectNode() + .put("key", annotationConstraint.key()) + .put("threshold", annotationConstraint.threshold()); + } + + /** + * Encodes a bandwidth constraint. + * + * @return JSON ObjectNode representing the constraint + */ + private ObjectNode encodeBandwidthConstraint() { + checkNotNull(constraint, "Bandwidth constraint cannot be null"); + final BandwidthConstraint bandwidthConstraint = + (BandwidthConstraint) constraint; + return context.mapper().createObjectNode() + .put("bandwidth", bandwidthConstraint.bandwidth().toDouble()); + } + + /** + * Encodes a lambda constraint. + * + * @return JSON ObjectNode representing the constraint + */ + private ObjectNode encodeLambdaConstraint() { + checkNotNull(constraint, "Lambda constraint cannot be null"); + final LambdaConstraint lambdaConstraint = + (LambdaConstraint) constraint; + + return context.mapper().createObjectNode() + .put("lambda", lambdaConstraint.lambda().toInt()); + } + + /** + * Encodes a link type constraint. + * + * @return JSON ObjectNode representing the constraint + */ + private ObjectNode encodeLinkTypeConstraint() { + checkNotNull(constraint, "Link type constraint cannot be null"); + + final LinkTypeConstraint linkTypeConstraint = + (LinkTypeConstraint) constraint; + + final ObjectNode result = context.mapper().createObjectNode() + .put(ConstraintCodec.INCLUSIVE, linkTypeConstraint.isInclusive()); + + final ArrayNode jsonTypes = result.putArray(ConstraintCodec.TYPES); + + if (linkTypeConstraint.types() != null) { + for (Link.Type type : linkTypeConstraint.types()) { + jsonTypes.add(type.name()); + } + } + + return result; + } + + /** + * Encodes the constraint in JSON. + * + * @return JSON node + */ + public ObjectNode encode() { + final ObjectNode result; + if (constraint instanceof BandwidthConstraint) { + result = encodeBandwidthConstraint(); + } else if (constraint instanceof LambdaConstraint) { + result = encodeLambdaConstraint(); + } else if (constraint instanceof LinkTypeConstraint) { + result = encodeLinkTypeConstraint(); + } else if (constraint instanceof AnnotationConstraint) { + result = encodeAnnotationConstraint(); + } else if (constraint instanceof LatencyConstraint) { + result = encodeLatencyConstraint(); + } else if (constraint instanceof ObstacleConstraint) { + result = encodeObstacleConstraint(); + } else if (constraint instanceof WaypointConstraint) { + result = encodeWaypointConstraint(); + } else { + result = context.mapper().createObjectNode(); + } + + result.put(ConstraintCodec.TYPE, constraint.getClass().getSimpleName()); + return result; + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java new file mode 100644 index 00000000..a962c0dd --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java @@ -0,0 +1,396 @@ +/* + * 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 java.util.EnumMap; + +import org.onosproject.codec.CodecContext; +import org.onosproject.net.OchSignal; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.EthCriterion; +import org.onosproject.net.flow.criteria.EthTypeCriterion; +import org.onosproject.net.flow.criteria.IPCriterion; +import org.onosproject.net.flow.criteria.IPDscpCriterion; +import org.onosproject.net.flow.criteria.IPEcnCriterion; +import org.onosproject.net.flow.criteria.IPProtocolCriterion; +import org.onosproject.net.flow.criteria.IPv6ExthdrFlagsCriterion; +import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion; +import org.onosproject.net.flow.criteria.IPv6NDLinkLayerAddressCriterion; +import org.onosproject.net.flow.criteria.IPv6NDTargetAddressCriterion; +import org.onosproject.net.flow.criteria.IcmpCodeCriterion; +import org.onosproject.net.flow.criteria.IcmpTypeCriterion; +import org.onosproject.net.flow.criteria.Icmpv6CodeCriterion; +import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion; +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.PortCriterion; +import org.onosproject.net.flow.criteria.SctpPortCriterion; +import org.onosproject.net.flow.criteria.TcpPortCriterion; +import org.onosproject.net.flow.criteria.TunnelIdCriterion; +import org.onosproject.net.flow.criteria.UdpPortCriterion; +import org.onosproject.net.flow.criteria.VlanIdCriterion; +import org.onosproject.net.flow.criteria.VlanPcpCriterion; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Encode portion of the criterion codec. + */ +public final class EncodeCriterionCodecHelper { + + private final Criterion criterion; + private final CodecContext context; + + private final EnumMap formatMap; + + /** + * Creates an encoder object for a criterion. + * Initializes the formatter lookup map for the criterion subclasses. + * + * @param criterion Criterion to encode + * @param context context of the JSON encoding + */ + public EncodeCriterionCodecHelper(Criterion criterion, CodecContext context) { + this.criterion = criterion; + this.context = context; + + formatMap = new EnumMap<>(Criterion.Type.class); + + formatMap.put(Criterion.Type.IN_PORT, new FormatInPort()); + formatMap.put(Criterion.Type.IN_PHY_PORT, new FormatInPort()); + formatMap.put(Criterion.Type.METADATA, new FormatMetadata()); + formatMap.put(Criterion.Type.ETH_DST, new FormatEth()); + formatMap.put(Criterion.Type.ETH_SRC, new FormatEth()); + formatMap.put(Criterion.Type.ETH_TYPE, new FormatEthType()); + formatMap.put(Criterion.Type.VLAN_VID, new FormatVlanVid()); + formatMap.put(Criterion.Type.VLAN_PCP, new FormatVlanPcp()); + formatMap.put(Criterion.Type.IP_DSCP, new FormatIpDscp()); + formatMap.put(Criterion.Type.IP_ECN, new FormatIpEcn()); + formatMap.put(Criterion.Type.IP_PROTO, new FormatIpProto()); + formatMap.put(Criterion.Type.IPV4_SRC, new FormatIp()); + formatMap.put(Criterion.Type.IPV4_DST, new FormatIp()); + formatMap.put(Criterion.Type.TCP_SRC, new FormatTcp()); + formatMap.put(Criterion.Type.TCP_DST, new FormatTcp()); + formatMap.put(Criterion.Type.UDP_SRC, new FormatUdp()); + formatMap.put(Criterion.Type.UDP_DST, new FormatUdp()); + formatMap.put(Criterion.Type.SCTP_SRC, new FormatSctp()); + formatMap.put(Criterion.Type.SCTP_DST, new FormatSctp()); + formatMap.put(Criterion.Type.ICMPV4_TYPE, new FormatIcmpV4Type()); + formatMap.put(Criterion.Type.ICMPV4_CODE, new FormatIcmpV4Code()); + formatMap.put(Criterion.Type.IPV6_SRC, new FormatIp()); + formatMap.put(Criterion.Type.IPV6_DST, new FormatIp()); + formatMap.put(Criterion.Type.IPV6_FLABEL, new FormatIpV6FLabel()); + formatMap.put(Criterion.Type.ICMPV6_TYPE, new FormatIcmpV6Type()); + formatMap.put(Criterion.Type.ICMPV6_CODE, new FormatIcmpV6Code()); + formatMap.put(Criterion.Type.IPV6_ND_TARGET, new FormatV6NDTarget()); + formatMap.put(Criterion.Type.IPV6_ND_SLL, new FormatV6NDTll()); + formatMap.put(Criterion.Type.IPV6_ND_TLL, new FormatV6NDTll()); + formatMap.put(Criterion.Type.MPLS_LABEL, new FormatMplsLabel()); + formatMap.put(Criterion.Type.IPV6_EXTHDR, new FormatIpV6Exthdr()); + formatMap.put(Criterion.Type.OCH_SIGID, new FormatOchSigId()); + formatMap.put(Criterion.Type.OCH_SIGTYPE, new FormatOchSigType()); + formatMap.put(Criterion.Type.TUNNEL_ID, new FormatTunnelId()); + formatMap.put(Criterion.Type.DUMMY, new FormatDummyType()); + + // Currently unimplemented + formatMap.put(Criterion.Type.ARP_OP, new FormatUnknown()); + formatMap.put(Criterion.Type.ARP_SPA, new FormatUnknown()); + formatMap.put(Criterion.Type.ARP_TPA, new FormatUnknown()); + formatMap.put(Criterion.Type.ARP_SHA, new FormatUnknown()); + formatMap.put(Criterion.Type.ARP_THA, new FormatUnknown()); + formatMap.put(Criterion.Type.MPLS_TC, new FormatUnknown()); + formatMap.put(Criterion.Type.MPLS_BOS, new FormatUnknown()); + formatMap.put(Criterion.Type.PBB_ISID, new FormatUnknown()); + formatMap.put(Criterion.Type.UNASSIGNED_40, new FormatUnknown()); + formatMap.put(Criterion.Type.PBB_UCA, new FormatUnknown()); + formatMap.put(Criterion.Type.TCP_FLAGS, new FormatUnknown()); + formatMap.put(Criterion.Type.ACTSET_OUTPUT, new FormatUnknown()); + formatMap.put(Criterion.Type.PACKET_TYPE, new FormatUnknown()); + } + + private interface CriterionTypeFormatter { + ObjectNode encodeCriterion(ObjectNode root, Criterion criterion); + } + + private static class FormatUnknown implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + return root; + } + } + + private static class FormatInPort implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final PortCriterion portCriterion = (PortCriterion) criterion; + return root.put(CriterionCodec.PORT, portCriterion.port().toLong()); + } + } + + private static class FormatMetadata implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final MetadataCriterion metadataCriterion = + (MetadataCriterion) criterion; + return root.put(CriterionCodec.METADATA, metadataCriterion.metadata()); + } + } + + private static class FormatEth implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final EthCriterion ethCriterion = (EthCriterion) criterion; + return root.put(CriterionCodec.MAC, ethCriterion.mac().toString()); + } + } + + private static class FormatEthType implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final EthTypeCriterion ethTypeCriterion = + (EthTypeCriterion) criterion; + return root.put(CriterionCodec.ETH_TYPE, ethTypeCriterion.ethType().toShort()); + } + } + + private static class FormatVlanVid implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final VlanIdCriterion vlanIdCriterion = + (VlanIdCriterion) criterion; + return root.put(CriterionCodec.VLAN_ID, vlanIdCriterion.vlanId().toShort()); + } + } + + private static class FormatVlanPcp implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final VlanPcpCriterion vlanPcpCriterion = + (VlanPcpCriterion) criterion; + return root.put(CriterionCodec.PRIORITY, vlanPcpCriterion.priority()); + } + } + + private static class FormatIpDscp implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final IPDscpCriterion ipDscpCriterion = + (IPDscpCriterion) criterion; + return root.put(CriterionCodec.IP_DSCP, ipDscpCriterion.ipDscp()); + } + } + + private static class FormatIpEcn implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final IPEcnCriterion ipEcnCriterion = + (IPEcnCriterion) criterion; + return root.put(CriterionCodec.IP_ECN, ipEcnCriterion.ipEcn()); + } + } + + private static class FormatIpProto implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final IPProtocolCriterion iPProtocolCriterion = + (IPProtocolCriterion) criterion; + return root.put(CriterionCodec.PROTOCOL, iPProtocolCriterion.protocol()); + } + } + + private static class FormatIp implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final IPCriterion iPCriterion = (IPCriterion) criterion; + return root.put(CriterionCodec.IP, iPCriterion.ip().toString()); + } + } + + private static class FormatTcp implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final TcpPortCriterion tcpPortCriterion = + (TcpPortCriterion) criterion; + return root.put(CriterionCodec.TCP_PORT, tcpPortCriterion.tcpPort().toInt()); + } + } + + private static class FormatUdp implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final UdpPortCriterion udpPortCriterion = + (UdpPortCriterion) criterion; + return root.put(CriterionCodec.UDP_PORT, udpPortCriterion.udpPort().toInt()); + } + } + + private static class FormatSctp implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final SctpPortCriterion sctpPortCriterion = + (SctpPortCriterion) criterion; + return root.put(CriterionCodec.SCTP_PORT, sctpPortCriterion.sctpPort().toInt()); + } + } + + private static class FormatIcmpV4Type implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final IcmpTypeCriterion icmpTypeCriterion = + (IcmpTypeCriterion) criterion; + return root.put(CriterionCodec.ICMP_TYPE, icmpTypeCriterion.icmpType()); + } + } + + private static class FormatIcmpV4Code implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final IcmpCodeCriterion icmpCodeCriterion = + (IcmpCodeCriterion) criterion; + return root.put(CriterionCodec.ICMP_CODE, icmpCodeCriterion.icmpCode()); + } + } + + private static class FormatIpV6FLabel implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final IPv6FlowLabelCriterion ipv6FlowLabelCriterion = + (IPv6FlowLabelCriterion) criterion; + return root.put(CriterionCodec.FLOW_LABEL, ipv6FlowLabelCriterion.flowLabel()); + } + } + + private static class FormatIcmpV6Type implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final Icmpv6TypeCriterion icmpv6TypeCriterion = + (Icmpv6TypeCriterion) criterion; + return root.put(CriterionCodec.ICMPV6_TYPE, icmpv6TypeCriterion.icmpv6Type()); + } + } + + private static class FormatIcmpV6Code implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final Icmpv6CodeCriterion icmpv6CodeCriterion = + (Icmpv6CodeCriterion) criterion; + return root.put(CriterionCodec.ICMPV6_CODE, icmpv6CodeCriterion.icmpv6Code()); + } + } + + private static class FormatV6NDTarget implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final IPv6NDTargetAddressCriterion ipv6NDTargetAddressCriterion + = (IPv6NDTargetAddressCriterion) criterion; + return root.put(CriterionCodec.TARGET_ADDRESS, ipv6NDTargetAddressCriterion.targetAddress().toString()); + } + } + + private static class FormatV6NDTll implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final IPv6NDLinkLayerAddressCriterion ipv6NDLinkLayerAddressCriterion + = (IPv6NDLinkLayerAddressCriterion) criterion; + return root.put(CriterionCodec.MAC, ipv6NDLinkLayerAddressCriterion.mac().toString()); + } + } + + private static class FormatMplsLabel implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final MplsCriterion mplsCriterion = + (MplsCriterion) criterion; + return root.put(CriterionCodec.LABEL, mplsCriterion.label().toInt()); + } + } + + private static class FormatIpV6Exthdr implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final IPv6ExthdrFlagsCriterion exthdrCriterion = + (IPv6ExthdrFlagsCriterion) criterion; + return root.put(CriterionCodec.EXT_HDR_FLAGS, exthdrCriterion.exthdrFlags()); + } + } + + private static class FormatOchSigId implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + OchSignal ochSignal = ((OchSignalCriterion) criterion).lambda(); + ObjectNode child = root.putObject(CriterionCodec.OCH_SIGNAL_ID); + + child.put(CriterionCodec.GRID_TYPE, ochSignal.gridType().name()); + child.put(CriterionCodec.CHANNEL_SPACING, ochSignal.channelSpacing().name()); + child.put(CriterionCodec.SPACING_MULIPLIER, ochSignal.spacingMultiplier()); + child.put(CriterionCodec.SLOT_GRANULARITY, ochSignal.slotGranularity()); + + return root; + } + } + + private static class FormatOchSigType implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final OchSignalTypeCriterion ochSignalTypeCriterion = + (OchSignalTypeCriterion) criterion; + return root.put("ochSignalType", ochSignalTypeCriterion.signalType().name()); + } + } + + private static class FormatTunnelId implements CriterionTypeFormatter { + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + final TunnelIdCriterion tunnelIdCriterion = + (TunnelIdCriterion) criterion; + return root.put(CriterionCodec.TUNNEL_ID, tunnelIdCriterion.tunnelId()); + } + } + + private class FormatDummyType implements CriterionTypeFormatter { + + @Override + public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) { + checkNotNull(criterion, "Criterion cannot be null"); + + return root.put(CriterionCodec.TYPE, criterion.type().toString()); + + } + } + + /** + * Encodes a criterion into a JSON node. + * + * @return encoded JSON object for the given criterion + */ + public ObjectNode encode() { + final ObjectNode result = context.mapper().createObjectNode() + .put(CriterionCodec.TYPE, criterion.type().toString()); + + CriterionTypeFormatter formatter = + checkNotNull( + formatMap.get(criterion.type()), + "No formatter found for criterion type " + + criterion.type().toString()); + + return formatter.encodeCriterion(result, criterion); + } + +} 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 new file mode 100644 index 00000000..d61cf38b --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java @@ -0,0 +1,243 @@ +/* + * 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.net.OchSignal; +import org.onosproject.net.flow.instructions.Instruction; +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.flow.instructions.L4ModificationInstruction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * JSON encoding of Instructions. + */ +public final class EncodeInstructionCodecHelper { + protected static final Logger log = LoggerFactory.getLogger(EncodeInstructionCodecHelper.class); + private final Instruction instruction; + private final CodecContext context; + + /** + * Creates an instruction object encoder. + * + * @param instruction instruction to encode + * @param context codec context for the encoding + */ + public EncodeInstructionCodecHelper(Instruction instruction, CodecContext context) { + this.instruction = instruction; + this.context = context; + } + + + /** + * Encode an L0 modification instruction. + * + * @param result json node that the instruction attributes are added to + */ + private void encodeL0(ObjectNode result) { + L0ModificationInstruction instruction = + (L0ModificationInstruction) this.instruction; + result.put(InstructionCodec.SUBTYPE, instruction.subtype().name()); + + switch (instruction.subtype()) { + case LAMBDA: + final L0ModificationInstruction.ModLambdaInstruction modLambdaInstruction = + (L0ModificationInstruction.ModLambdaInstruction) instruction; + result.put(InstructionCodec.LAMBDA, modLambdaInstruction.lambda()); + break; + + case OCH: + L0ModificationInstruction.ModOchSignalInstruction ochSignalInstruction = + (L0ModificationInstruction.ModOchSignalInstruction) instruction; + OchSignal ochSignal = ochSignalInstruction.lambda(); + result.put(InstructionCodec.GRID_TYPE, ochSignal.gridType().name()); + result.put(InstructionCodec.CHANNEL_SPACING, ochSignal.channelSpacing().name()); + result.put(InstructionCodec.SPACING_MULTIPLIER, ochSignal.spacingMultiplier()); + result.put(InstructionCodec.SLOT_GRANULARITY, ochSignal.slotGranularity()); + break; + + default: + log.info("Cannot convert L0 subtype of {}", instruction.subtype()); + } + } + + /** + * Encode an L2 modification instruction. + * + * @param result json node that the instruction attributes are added to + */ + private void encodeL2(ObjectNode result) { + L2ModificationInstruction instruction = + (L2ModificationInstruction) this.instruction; + result.put(InstructionCodec.SUBTYPE, instruction.subtype().name()); + + switch (instruction.subtype()) { + case ETH_SRC: + case ETH_DST: + final L2ModificationInstruction.ModEtherInstruction modEtherInstruction = + (L2ModificationInstruction.ModEtherInstruction) instruction; + result.put(InstructionCodec.MAC, modEtherInstruction.mac().toString()); + break; + + case VLAN_ID: + final L2ModificationInstruction.ModVlanIdInstruction modVlanIdInstruction = + (L2ModificationInstruction.ModVlanIdInstruction) instruction; + result.put(InstructionCodec.VLAN_ID, modVlanIdInstruction.vlanId().toShort()); + break; + + case VLAN_PCP: + final L2ModificationInstruction.ModVlanPcpInstruction modVlanPcpInstruction = + (L2ModificationInstruction.ModVlanPcpInstruction) instruction; + result.put(InstructionCodec.VLAN_PCP, modVlanPcpInstruction.vlanPcp()); + break; + + case MPLS_LABEL: + final L2ModificationInstruction.ModMplsLabelInstruction modMplsLabelInstruction = + (L2ModificationInstruction.ModMplsLabelInstruction) instruction; + result.put(InstructionCodec.MPLS_LABEL, modMplsLabelInstruction.mplsLabel().toInt()); + break; + + case MPLS_PUSH: + final L2ModificationInstruction.PushHeaderInstructions pushHeaderInstructions = + (L2ModificationInstruction.PushHeaderInstructions) instruction; + + result.put(InstructionCodec.ETHERNET_TYPE, + pushHeaderInstructions.ethernetType().toShort()); + break; + + case TUNNEL_ID: + final L2ModificationInstruction.ModTunnelIdInstruction modTunnelIdInstruction = + (L2ModificationInstruction.ModTunnelIdInstruction) instruction; + result.put(InstructionCodec.TUNNEL_ID, modTunnelIdInstruction.tunnelId()); + break; + + default: + log.info("Cannot convert L2 subtype of {}", instruction.subtype()); + break; + } + } + + /** + * Encode an L3 modification instruction. + * + * @param result json node that the instruction attributes are added to + */ + private void encodeL3(ObjectNode result) { + L3ModificationInstruction instruction = + (L3ModificationInstruction) this.instruction; + result.put(InstructionCodec.SUBTYPE, instruction.subtype().name()); + switch (instruction.subtype()) { + case IPV4_SRC: + case IPV4_DST: + case IPV6_SRC: + case IPV6_DST: + final L3ModificationInstruction.ModIPInstruction modIPInstruction = + (L3ModificationInstruction.ModIPInstruction) instruction; + result.put(InstructionCodec.IP, modIPInstruction.ip().toString()); + break; + + case IPV6_FLABEL: + final L3ModificationInstruction.ModIPv6FlowLabelInstruction + modFlowLabelInstruction = + (L3ModificationInstruction.ModIPv6FlowLabelInstruction) instruction; + result.put(InstructionCodec.FLOW_LABEL, modFlowLabelInstruction.flowLabel()); + break; + + default: + log.info("Cannot convert L3 subtype of {}", instruction.subtype()); + break; + } + } + + /** + * Encode a L4 modification instruction. + * + * @param result json node that the instruction attributes are added to + */ + private void encodeL4(ObjectNode result) { + L4ModificationInstruction instruction = + (L4ModificationInstruction) this.instruction; + result.put(InstructionCodec.SUBTYPE, instruction.subtype().name()); + switch (instruction.subtype()) { + case TCP_DST: + case TCP_SRC: + final L4ModificationInstruction.ModTransportPortInstruction modTcpPortInstruction = + (L4ModificationInstruction.ModTransportPortInstruction) instruction; + result.put(InstructionCodec.TCP_PORT, modTcpPortInstruction.port().toInt()); + break; + + case UDP_DST: + case UDP_SRC: + final L4ModificationInstruction.ModTransportPortInstruction modUdpPortInstruction = + (L4ModificationInstruction.ModTransportPortInstruction) instruction; + result.put(InstructionCodec.UDP_PORT, modUdpPortInstruction.port().toInt()); + break; + + default: + log.info("Cannot convert L4 subtype of {}", instruction.subtype()); + break; + } + } + + /** + * Encodes the given instruction into JSON. + * + * @return JSON object node representing the instruction + */ + public ObjectNode encode() { + final ObjectNode result = context.mapper().createObjectNode() + .put(InstructionCodec.TYPE, instruction.type().toString()); + + switch (instruction.type()) { + case OUTPUT: + final Instructions.OutputInstruction outputInstruction = + (Instructions.OutputInstruction) instruction; + result.put(InstructionCodec.PORT, outputInstruction.port().toLong()); + break; + + case DROP: + break; + + case L0MODIFICATION: + encodeL0(result); + break; + + case L2MODIFICATION: + encodeL2(result); + break; + + case L3MODIFICATION: + encodeL3(result); + break; + + case L4MODIFICATION: + encodeL4(result); + break; + + default: + log.info("Cannot convert instruction type of {}", instruction.type()); + break; + } + return result; + } + +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EthernetCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EthernetCodec.java new file mode 100644 index 00000000..f56bca46 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/EthernetCodec.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.codec.impl; + +import org.onlab.packet.Ethernet; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Ethernet codec. + */ +public final class EthernetCodec extends JsonCodec { + + protected static final Logger log = LoggerFactory.getLogger(CriterionCodec.class); + + @Override + public ObjectNode encode(Ethernet ethernet, CodecContext context) { + checkNotNull(ethernet, "Ethernet cannot be null"); + + final ObjectNode result = context.mapper().createObjectNode() + .put("vlanId", ethernet.getVlanID()) + .put("etherType", ethernet.getEtherType()) + .put("priorityCode", ethernet.getPriorityCode()) + .put("pad", ethernet.isPad()); + + if (ethernet.getDestinationMAC() != null) { + result.put("destMac", + ethernet.getDestinationMAC().toString()); + } + + if (ethernet.getSourceMAC() != null) { + result.put("srcMac", + ethernet.getSourceMAC().toString()); + } + + return result; + } + +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/FlowEntryCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/FlowEntryCodec.java new file mode 100644 index 00000000..923bdf2b --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/FlowEntryCodec.java @@ -0,0 +1,70 @@ +/* + * Copyright 2014-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.core.CoreService; +import org.onosproject.net.flow.FlowEntry; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Flow entry JSON codec. + */ +public final class FlowEntryCodec extends JsonCodec { + + @Override + public ObjectNode encode(FlowEntry flowEntry, CodecContext context) { + checkNotNull(flowEntry, "Flow entry cannot be null"); + + CoreService service = context.getService(CoreService.class); + + final ObjectNode result = context.mapper().createObjectNode() + .put("id", Long.toString(flowEntry.id().value())) + .put("appId", service.getAppId(flowEntry.appId()).name()) + .put("groupId", flowEntry.groupId().id()) + .put("priority", flowEntry.priority()) + .put("timeout", flowEntry.timeout()) + .put("isPermanent", flowEntry.isPermanent()) + .put("deviceId", flowEntry.deviceId().toString()) + .put("state", flowEntry.state().toString()) + .put("life", flowEntry.life()) + .put("packets", flowEntry.packets()) + .put("bytes", flowEntry.bytes()) + .put("lastSeen", flowEntry.lastSeen()); + + if (flowEntry.treatment() != null) { + final JsonCodec treatmentCodec = + context.codec(TrafficTreatment.class); + result.set("treatment", treatmentCodec.encode(flowEntry.treatment(), context)); + } + + if (flowEntry.selector() != null) { + final JsonCodec selectorCodec = + context.codec(TrafficSelector.class); + result.set("selector", selectorCodec.encode(flowEntry.selector(), context)); + } + + return result; + } + +} + diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/FlowRuleCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/FlowRuleCodec.java new file mode 100644 index 00000000..6c02841e --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/FlowRuleCodec.java @@ -0,0 +1,94 @@ +/* + * 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.core.CoreService; +import org.onosproject.net.DeviceId; +import org.onosproject.net.flow.DefaultFlowRule; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static org.onlab.util.Tools.nullIsIllegal; + +/** + * Flow rule JSON codec. + */ +public final class FlowRuleCodec extends JsonCodec { + + private static final String PRIORITY = "priority"; + private static final String TIMEOUT = "timeout"; + private static final String IS_PERMANENT = "isPermanent"; + private static final String DEVICE_ID = "deviceId"; + private static final String TREATMENT = "treatment"; + private static final String SELECTOR = "selector"; + private static final String MISSING_MEMBER_MESSAGE = + " member is required in FlowRule"; + public static final String REST_APP_ID = "org.onosproject.rest"; + + + @Override + public FlowRule decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + FlowRule.Builder resultBuilder = new DefaultFlowRule.Builder(); + + CoreService coreService = context.getService(CoreService.class); + resultBuilder.fromApp(coreService + .registerApplication(REST_APP_ID)); + + int priority = nullIsIllegal(json.get(PRIORITY), + PRIORITY + MISSING_MEMBER_MESSAGE).asInt(); + resultBuilder.withPriority(priority); + + boolean isPermanent = nullIsIllegal(json.get(IS_PERMANENT), + IS_PERMANENT + MISSING_MEMBER_MESSAGE).asBoolean(); + if (isPermanent) { + resultBuilder.makePermanent(); + } else { + resultBuilder.makeTemporary(nullIsIllegal(json.get(TIMEOUT), + TIMEOUT + + MISSING_MEMBER_MESSAGE + + " if the flow is temporary").asInt()); + } + + DeviceId deviceId = DeviceId.deviceId(nullIsIllegal(json.get(DEVICE_ID), + DEVICE_ID + MISSING_MEMBER_MESSAGE).asText()); + resultBuilder.forDevice(deviceId); + + ObjectNode treatmentJson = get(json, TREATMENT); + if (treatmentJson != null) { + JsonCodec treatmentCodec = + context.codec(TrafficTreatment.class); + resultBuilder.withTreatment(treatmentCodec.decode(treatmentJson, context)); + } + + ObjectNode selectorJson = get(json, SELECTOR); + if (selectorJson != null) { + JsonCodec selectorCodec = + context.codec(TrafficSelector.class); + resultBuilder.withSelector(selectorCodec.decode(selectorJson, context)); + } + + return resultBuilder.build(); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/GroupBucketCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/GroupBucketCodec.java new file mode 100644 index 00000000..c710514f --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/GroupBucketCodec.java @@ -0,0 +1,64 @@ +/* + * 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.TrafficTreatment; +import org.onosproject.net.group.GroupBucket; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Group bucket JSON codec. + */ +public class GroupBucketCodec extends JsonCodec { + + private static final String TYPE = "type"; + private static final String TREATMENT = "treatment"; + private static final String WEIGHT = "weight"; + private static final String WATCH_PORT = "watchPort"; + private static final String WATCH_GROUP = "watchGroup"; + private static final String PACKETS = "packets"; + private static final String BYTES = "bytes"; + + @Override + public ObjectNode encode(GroupBucket bucket, CodecContext context) { + checkNotNull(bucket, "Driver cannot be null"); + + ObjectNode result = context.mapper().createObjectNode() + .put(TYPE, bucket.type().toString()) + .put(WEIGHT, bucket.weight()) + .put(PACKETS, bucket.packets()) + .put(BYTES, bucket.bytes()); + + if (bucket.watchPort() != null) { + result.put(WATCH_PORT, bucket.watchPort().toString()); + } + + if (bucket.watchGroup() != null) { + result.put(WATCH_GROUP, bucket.watchGroup().toString()); + } + + if (bucket.treatment() != null) { + result.set(TREATMENT, context.codec(TrafficTreatment.class).encode(bucket.treatment(), context)); + } + + return result; + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/GroupCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/GroupCodec.java new file mode 100644 index 00000000..a2f33cee --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/GroupCodec.java @@ -0,0 +1,79 @@ +/* + * 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.group.Group; +import org.onosproject.net.group.GroupBucket; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Group JSON codec. + */ +public final class GroupCodec extends JsonCodec { + // JSON field names + private static final String ID = "id"; + private static final String STATE = "state"; + private static final String LIFE = "life"; + private static final String PACKETS = "packets"; + private static final String BYTES = "bytes"; + private static final String REFERENCE_COUNT = "referenceCount"; + private static final String TYPE = "type"; + private static final String DEVICE_ID = "deviceId"; + private static final String APP_ID = "appId"; + private static final String APP_COOKIE = "appCookie"; + private static final String GIVEN_GROUP_ID = "givenGroupId"; + private static final String BUCKETS = "buckets"; + + @Override + public ObjectNode encode(Group group, CodecContext context) { + checkNotNull(group, "Group cannot be null"); + ObjectNode result = context.mapper().createObjectNode() + .put(ID, group.id().toString()) + .put(STATE, group.state().toString()) + .put(LIFE, group.life()) + .put(PACKETS, group.packets()) + .put(BYTES, group.bytes()) + .put(REFERENCE_COUNT, group.referenceCount()) + .put(TYPE, group.type().toString()) + .put(DEVICE_ID, group.deviceId().toString()); + + if (group.appId() != null) { + result.put(APP_ID, group.appId().toString()); + } + + if (group.appCookie() != null) { + result.put(APP_COOKIE, group.appCookie().toString()); + } + + if (group.givenGroupId() != null) { + result.put(GIVEN_GROUP_ID, group.givenGroupId()); + } + + ArrayNode buckets = context.mapper().createArrayNode(); + group.buckets().buckets().forEach(bucket -> { + ObjectNode bucketJson = context.codec(GroupBucket.class).encode(bucket, context); + buckets.add(bucketJson); + }); + result.set(BUCKETS, buckets); + return result; + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java new file mode 100644 index 00000000..a2402728 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/HostCodec.java @@ -0,0 +1,55 @@ +/* + * Copyright 2014-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.onlab.packet.IpAddress; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.Host; +import org.onosproject.net.HostLocation; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Host JSON codec. + */ +public final class HostCodec extends AnnotatedCodec { + + @Override + public ObjectNode encode(Host host, CodecContext context) { + checkNotNull(host, "Host cannot be null"); + final JsonCodec locationCodec = + context.codec(HostLocation.class); + final ObjectNode result = context.mapper().createObjectNode() + .put("id", host.id().toString()) + .put("mac", host.mac().toString()) + .put("vlan", host.vlan().toString()); + + final ArrayNode jsonIpAddresses = result.putArray("ipAddresses"); + for (final IpAddress ipAddress : host.ipAddresses()) { + jsonIpAddresses.add(ipAddress.toString()); + } + result.set("ipAddresses", jsonIpAddresses); + result.set("location", locationCodec.encode(host.location(), context)); + + return annotate(result, host, context); + } + +} + diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/HostLocationCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/HostLocationCodec.java new file mode 100644 index 00000000..f8f616d0 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/HostLocationCodec.java @@ -0,0 +1,39 @@ +/* + * Copyright 2014-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.HostLocation; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Host JSON codec. + */ +public final class HostLocationCodec extends JsonCodec { + + @Override + public ObjectNode encode(HostLocation hostLocation, CodecContext context) { + checkNotNull(hostLocation, "Host location cannot be null"); + return context.mapper().createObjectNode() + .put("elementId", hostLocation.elementId().toString()) + .put("port", hostLocation.port().toString()); + } + +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/HostToHostIntentCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/HostToHostIntentCodec.java new file mode 100644 index 00000000..597ab55c --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/HostToHostIntentCodec.java @@ -0,0 +1,70 @@ +/* + * 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.HostId; +import org.onosproject.net.intent.ConnectivityIntent; +import org.onosproject.net.intent.HostToHostIntent; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.nullIsIllegal; + +/** + * Host to host intent codec. + */ +public final class HostToHostIntentCodec extends JsonCodec { + + private static final String ONE = "one"; + private static final String TWO = "two"; + + @Override + public ObjectNode encode(HostToHostIntent intent, CodecContext context) { + checkNotNull(intent, "Host to host intent cannot be null"); + + final JsonCodec connectivityIntentCodec = + context.codec(ConnectivityIntent.class); + final ObjectNode result = connectivityIntentCodec.encode(intent, context); + + final String one = intent.one().toString(); + final String two = intent.two().toString(); + result.put(ONE, one); + result.put(TWO, two); + + return result; + } + + @Override + public HostToHostIntent decode(ObjectNode json, CodecContext context) { + HostToHostIntent.Builder builder = HostToHostIntent.builder(); + + IntentCodec.intentAttributes(json, context, builder); + ConnectivityIntentCodec.intentAttributes(json, context, builder); + + String one = nullIsIllegal(json.get(ONE), + ONE + IntentCodec.MISSING_MEMBER_MESSAGE).asText(); + builder.one(HostId.hostId(one)); + + String two = nullIsIllegal(json.get(TWO), + TWO + IntentCodec.MISSING_MEMBER_MESSAGE).asText(); + builder.two(HostId.hostId(two)); + + return builder.build(); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java new file mode 100644 index 00000000..f4d5008a --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java @@ -0,0 +1,73 @@ +/* + * 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.instructions.Instruction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Instruction codec. + */ +public final class InstructionCodec extends JsonCodec { + + protected static final Logger log = LoggerFactory.getLogger(InstructionCodec.class); + + protected static final String TYPE = "type"; + protected static final String SUBTYPE = "subtype"; + protected static final String PORT = "port"; + protected static final String MAC = "mac"; + protected static final String VLAN_ID = "vlanId"; + protected static final String VLAN_PCP = "vlanPcp"; + protected static final String MPLS_LABEL = "label"; + protected static final String IP = "ip"; + protected static final String FLOW_LABEL = "flowLabel"; + protected static final String LAMBDA = "lambda"; + protected static final String GRID_TYPE = "gridType"; + protected static final String CHANNEL_SPACING = "channelSpacing"; + protected static final String SPACING_MULTIPLIER = "spacingMultiplier"; + protected static final String SLOT_GRANULARITY = "slotGranularity"; + protected static final String ETHERNET_TYPE = "ethernetType"; + protected static final String TUNNEL_ID = "tunnelId"; + protected static final String TCP_PORT = "tcpPort"; + protected static final String UDP_PORT = "udpPort"; + + protected static final String MISSING_MEMBER_MESSAGE = + " member is required in Instruction"; + + + @Override + public ObjectNode encode(Instruction instruction, CodecContext context) { + checkNotNull(instruction, "Instruction cannot be null"); + + return new EncodeInstructionCodecHelper(instruction, context).encode(); + } + + @Override + public Instruction decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + return new DecodeInstructionCodecHelper(json).decode(); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/IntentCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/IntentCodec.java new file mode 100644 index 00000000..8613a964 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/IntentCodec.java @@ -0,0 +1,112 @@ +/* + * Copyright 2014-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.core.CoreService; +import org.onosproject.net.NetworkResource; +import org.onosproject.net.intent.HostToHostIntent; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.IntentState; +import org.onosproject.net.intent.PointToPointIntent; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.net.UrlEscapers; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.nullIsIllegal; + +/** + * Intent JSON codec. + */ +public final class IntentCodec extends JsonCodec { + + protected static final String TYPE = "type"; + protected static final String ID = "id"; + protected static final String APP_ID = "appId"; + protected static final String STATE = "state"; + protected static final String PRIORITY = "priority"; + protected static final String RESOURCES = "resources"; + protected static final String MISSING_MEMBER_MESSAGE = + " member is required in Intent"; + + @Override + public ObjectNode encode(Intent intent, CodecContext context) { + checkNotNull(intent, "Intent cannot be null"); + + final ObjectNode result = context.mapper().createObjectNode() + .put(TYPE, intent.getClass().getSimpleName()) + .put(ID, intent.id().toString()) + .put(APP_ID, UrlEscapers.urlPathSegmentEscaper() + .escape(intent.appId().name())); + + final ArrayNode jsonResources = result.putArray(RESOURCES); + + for (final NetworkResource resource : intent.resources()) { + jsonResources.add(resource.toString()); + } + + IntentService service = context.getService(IntentService.class); + IntentState state = service.getIntentState(intent.key()); + if (state != null) { + result.put(STATE, state.toString()); + } + + return result; + } + + @Override + public Intent decode(ObjectNode json, CodecContext context) { + checkNotNull(json, "JSON cannot be null"); + + String type = nullIsIllegal(json.get(TYPE), + TYPE + MISSING_MEMBER_MESSAGE).asText(); + + if (type.equals(PointToPointIntent.class.getSimpleName())) { + return context.codec(PointToPointIntent.class).decode(json, context); + } else if (type.equals(HostToHostIntent.class.getSimpleName())) { + return context.codec(HostToHostIntent.class).decode(json, context); + } + + throw new IllegalArgumentException("Intent type " + + type + " is not supported"); + } + + /** + * Extracts base intent specific attributes from a JSON object + * and adds them to a builder. + * + * @param json root JSON object + * @param context code context + * @param builder builder to use for storing the attributes + */ + public static void intentAttributes(ObjectNode json, CodecContext context, + Intent.Builder builder) { + String appId = nullIsIllegal(json.get(IntentCodec.APP_ID), + IntentCodec.APP_ID + IntentCodec.MISSING_MEMBER_MESSAGE).asText(); + CoreService service = context.getService(CoreService.class); + builder.appId(service.getAppId(appId)); + + JsonNode priorityJson = json.get(IntentCodec.PRIORITY); + if (priorityJson != null) { + builder.priority(priorityJson.asInt()); + } + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/LinkCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/LinkCodec.java new file mode 100644 index 00000000..14ee9b7c --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/LinkCodec.java @@ -0,0 +1,80 @@ +/* + * Copyright 2014-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 com.fasterxml.jackson.databind.node.ObjectNode; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.Annotations; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultLink; +import org.onosproject.net.Link; +import org.onosproject.net.Link.Type; +import org.onosproject.net.provider.ProviderId; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Link JSON codec. + */ +public final class LinkCodec extends AnnotatedCodec { + + // JSON field names + private static final String SRC = "src"; + private static final String DST = "dst"; + private static final String TYPE = "type"; + private static final String STATE = "state"; + + @Override + public ObjectNode encode(Link link, CodecContext context) { + checkNotNull(link, "Link cannot be null"); + JsonCodec codec = context.codec(ConnectPoint.class); + ObjectNode result = context.mapper().createObjectNode(); + result.set(SRC, codec.encode(link.src(), context)); + result.set(DST, codec.encode(link.dst(), context)); + result.put(TYPE, link.type().toString()); + if (link.state() != null) { + result.put(STATE, link.state().toString()); + } + return annotate(result, link, context); + } + + + /** + * {@inheritDoc} + * + * Note: ProviderId is not part of JSON representation. + * Returned object will have random ProviderId set. + */ + @Override + public Link decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + JsonCodec codec = context.codec(ConnectPoint.class); + // TODO: add providerId to JSON if we need to recover them. + ProviderId pid = new ProviderId("json", "LinkCodec"); + + ConnectPoint src = codec.decode(get(json, SRC), context); + ConnectPoint dst = codec.decode(get(json, DST), context); + Type type = Type.valueOf(json.get(TYPE).asText()); + Annotations annotations = extractAnnotations(json, context); + + return new DefaultLink(pid, src, dst, type, annotations); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/LoadCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/LoadCodec.java new file mode 100644 index 00000000..0e55592d --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/LoadCodec.java @@ -0,0 +1,45 @@ +/* + * 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.statistic.Load; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Codec for the Load class. + */ +public class LoadCodec extends JsonCodec { + + private static final String RATE = "rate"; + private static final String LATEST = "latest"; + private static final String VALID = "valid"; + private static final String TIME = "time"; + + @Override + public ObjectNode encode(Load load, CodecContext context) { + checkNotNull(load, "Load cannot be null"); + return context.mapper().createObjectNode() + .put(RATE, load.rate()) + .put(LATEST, load.latest()) + .put(VALID, load.isValid()) + .put(TIME, load.time()); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/PathCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/PathCodec.java new file mode 100644 index 00000000..58b48529 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/PathCodec.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.codec.impl; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.Link; +import org.onosproject.net.Path; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Path JSON codec. + */ +public final class PathCodec extends AnnotatedCodec { + @Override + public ObjectNode encode(Path path, CodecContext context) { + checkNotNull(path, "Path cannot be null"); + JsonCodec codec = context.codec(Link.class); + ObjectNode result = context.mapper() + .createObjectNode() + .put("cost", path.cost()); + ArrayNode jsonLinks = result.putArray("links"); + + for (Link link : path.links()) { + jsonLinks.add(codec.encode(link, context)); + } + + return annotate(result, path, context); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/PointToPointIntentCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/PointToPointIntentCodec.java new file mode 100644 index 00000000..20df4890 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/PointToPointIntentCodec.java @@ -0,0 +1,80 @@ +/* + * 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.ConnectPoint; +import org.onosproject.net.intent.ConnectivityIntent; +import org.onosproject.net.intent.PointToPointIntent; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.nullIsIllegal; + +/** + * Point to point intent codec. + */ +public final class PointToPointIntentCodec extends JsonCodec { + + private static final String INGRESS_POINT = "ingressPoint"; + private static final String EGRESS_POINT = "egressPoint"; + + @Override + public ObjectNode encode(PointToPointIntent intent, CodecContext context) { + checkNotNull(intent, "Point to point intent cannot be null"); + + final JsonCodec connectivityIntentCodec = + context.codec(ConnectivityIntent.class); + final ObjectNode result = connectivityIntentCodec.encode(intent, context); + + final JsonCodec connectPointCodec = + context.codec(ConnectPoint.class); + final ObjectNode ingress = + connectPointCodec.encode(intent.ingressPoint(), context); + final ObjectNode egress = + connectPointCodec.encode(intent.egressPoint(), context); + + result.set(INGRESS_POINT, ingress); + result.set(EGRESS_POINT, egress); + + return result; + } + + + @Override + public PointToPointIntent decode(ObjectNode json, CodecContext context) { + PointToPointIntent.Builder builder = PointToPointIntent.builder(); + + IntentCodec.intentAttributes(json, context, builder); + ConnectivityIntentCodec.intentAttributes(json, context, builder); + + ObjectNode ingressJson = nullIsIllegal(get(json, INGRESS_POINT), + INGRESS_POINT + IntentCodec.MISSING_MEMBER_MESSAGE); + ConnectPoint ingress = context.codec(ConnectPoint.class) + .decode(ingressJson, context); + builder.ingressPoint(ingress); + + ObjectNode egressJson = nullIsIllegal(get(json, EGRESS_POINT), + EGRESS_POINT + IntentCodec.MISSING_MEMBER_MESSAGE); + ConnectPoint egress = context.codec(ConnectPoint.class) + .decode(egressJson, context); + builder.egressPoint(egress); + + return builder.build(); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/PortCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/PortCodec.java new file mode 100644 index 00000000..c6f2ac76 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/PortCodec.java @@ -0,0 +1,160 @@ +/* + * Copyright 2014-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 com.fasterxml.jackson.databind.node.ObjectNode; + +import org.onlab.packet.ChassisId; +import org.onosproject.codec.CodecContext; +import org.onosproject.net.Annotations; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.DefaultPort; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Port; +import org.onosproject.net.Port.Type; +import org.onosproject.net.PortNumber; +import org.onosproject.net.provider.ProviderId; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Device port JSON codec. + */ +public final class PortCodec extends AnnotatedCodec { + + // JSON field names + private static final String ELEMENT = "element"; // DeviceId + private static final String PORT_NAME = "port"; + private static final String IS_ENABLED = "isEnabled"; + private static final String TYPE = "type"; + private static final String PORT_SPEED = "portSpeed"; + + // Special port name alias + private static final String PORT_NAME_LOCAL = "local"; + + @Override + public ObjectNode encode(Port port, CodecContext context) { + checkNotNull(port, "Port cannot be null"); + ObjectNode result = context.mapper().createObjectNode() + .put(ELEMENT, port.element().id().toString()) + .put(PORT_NAME, portName(port.number())) + .put(IS_ENABLED, port.isEnabled()) + .put(TYPE, port.type().toString().toLowerCase()) + .put(PORT_SPEED, port.portSpeed()); + return annotate(result, port, context); + } + + private String portName(PortNumber port) { + return port.equals(PortNumber.LOCAL) ? PORT_NAME_LOCAL : port.toString(); + } + + private static PortNumber portNumber(String portName) { + if (portName.equalsIgnoreCase(PORT_NAME_LOCAL)) { + return PortNumber.LOCAL; + } + + return PortNumber.portNumber(portName); + } + + + /** + * {@inheritDoc} + * + * Note: Result of {@link Port#element()} returned Port object, + * is not a full Device object. + * Only it's DeviceId can be used. + */ + @Override + public Port decode(ObjectNode json, CodecContext context) { + if (json == null || !json.isObject()) { + return null; + } + + DeviceId did = DeviceId.deviceId(json.get(ELEMENT).asText()); + Device device = new DummyDevice(did); + PortNumber number = portNumber(json.get(PORT_NAME).asText()); + boolean isEnabled = json.get(IS_ENABLED).asBoolean(); + Type type = Type.valueOf(json.get(TYPE).asText().toUpperCase()); + long portSpeed = json.get(PORT_SPEED).asLong(); + Annotations annotations = extractAnnotations(json, context); + + return new DefaultPort(device, number, isEnabled, type, portSpeed, annotations); + } + + + /** + * Dummy Device which only holds DeviceId. + */ + private static final class DummyDevice implements Device { + + private final DeviceId did; + + /** + * Constructs Dummy Device which only holds DeviceId. + * + * @param did device Id + */ + public DummyDevice(DeviceId did) { + this.did = did; + } + + @Override + public Annotations annotations() { + return DefaultAnnotations.EMPTY; + } + + @Override + public ProviderId providerId() { + return new ProviderId(did.uri().getScheme(), "PortCodec"); + } + + @Override + public DeviceId id() { + return did; + } + + @Override + public Type type() { + return Type.SWITCH; + } + + @Override + public String manufacturer() { + return "dummy"; + } + + @Override + public String hwVersion() { + return "0"; + } + + @Override + public String swVersion() { + return "0"; + } + + @Override + public String serialNumber() { + return "0"; + } + + @Override + public ChassisId chassisId() { + return new ChassisId(); + } + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TopologyClusterCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TopologyClusterCodec.java new file mode 100644 index 00000000..dc4c79a7 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TopologyClusterCodec.java @@ -0,0 +1,41 @@ +/* + * 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.topology.TopologyCluster; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Topology cluster JSON codec. + */ +public final class TopologyClusterCodec extends JsonCodec { + + @Override + public ObjectNode encode(TopologyCluster cluster, CodecContext context) { + checkNotNull(cluster, "Cluster cannot be null"); + + return context.mapper().createObjectNode() + .put("id", cluster.id().index()) + .put("deviceCount", cluster.deviceCount()) + .put("linkCount", cluster.linkCount()) + .put("root", cluster.root().toString()); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TopologyCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TopologyCodec.java new file mode 100644 index 00000000..f6529eb5 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TopologyCodec.java @@ -0,0 +1,41 @@ +/* + * 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.topology.Topology; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Topology JSON codec. + */ +public final class TopologyCodec extends JsonCodec { + + @Override + public ObjectNode encode(Topology topology, CodecContext context) { + checkNotNull(topology, "Topology cannot be null"); + + return context.mapper().createObjectNode() + .put("time", topology.time()) + .put("devices", topology.deviceCount()) + .put("links", topology.linkCount()) + .put("clusters", topology.clusterCount()); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TrafficSelectorCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TrafficSelectorCodec.java new file mode 100644 index 00000000..24ebef1a --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TrafficSelectorCodec.java @@ -0,0 +1,71 @@ +/* + * Copyright 2014-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 java.util.stream.IntStream; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.criteria.Criterion; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Traffic selector codec. + */ +public final class TrafficSelectorCodec extends JsonCodec { + private static final String CRITERIA = "criteria"; + + @Override + public ObjectNode encode(TrafficSelector selector, CodecContext context) { + checkNotNull(selector, "Traffic selector cannot be null"); + + final ObjectNode result = context.mapper().createObjectNode(); + final ArrayNode jsonCriteria = result.putArray(CRITERIA); + + if (selector.criteria() != null) { + final JsonCodec criterionCodec = + context.codec(Criterion.class); + for (final Criterion criterion : selector.criteria()) { + jsonCriteria.add(criterionCodec.encode(criterion, context)); + } + } + + return result; + } + + @Override + public TrafficSelector decode(ObjectNode json, CodecContext context) { + final JsonCodec criterionCodec = + context.codec(Criterion.class); + + JsonNode criteriaJson = json.get(CRITERIA); + TrafficSelector.Builder builder = DefaultTrafficSelector.builder(); + if (criteriaJson != null) { + IntStream.range(0, criteriaJson.size()) + .forEach(i -> builder.add( + criterionCodec.decode(get(criteriaJson, i), + context))); + } + return builder.build(); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TrafficTreatmentCodec.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TrafficTreatmentCodec.java new file mode 100644 index 00000000..0d7fb420 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/TrafficTreatmentCodec.java @@ -0,0 +1,76 @@ +/* + * Copyright 2014-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 java.util.stream.IntStream; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.instructions.Instruction; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Traffic treatment codec. + */ +public final class TrafficTreatmentCodec extends JsonCodec { + private static final String INSTRUCTIONS = "instructions"; + + @Override + public ObjectNode encode(TrafficTreatment treatment, CodecContext context) { + checkNotNull(treatment, "Traffic treatment cannot be null"); + + final ObjectNode result = context.mapper().createObjectNode(); + final ArrayNode jsonInstructions = result.putArray(INSTRUCTIONS); + + final JsonCodec instructionCodec = + context.codec(Instruction.class); + + for (final Instruction instruction : treatment.immediate()) { + jsonInstructions.add(instructionCodec.encode(instruction, context)); + } + + final ArrayNode jsonDeferred = result.putArray("deferred"); + + for (final Instruction instruction : treatment.deferred()) { + jsonDeferred.add(instructionCodec.encode(instruction, context)); + } + + return result; + } + + @Override + public TrafficTreatment decode(ObjectNode json, CodecContext context) { + final JsonCodec instructionsCodec = + context.codec(Instruction.class); + + JsonNode instructionsJson = json.get(INSTRUCTIONS); + TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); + if (instructionsJson != null) { + IntStream.range(0, instructionsJson.size()) + .forEach(i -> builder.add( + instructionsCodec.decode(get(instructionsJson, i), + context))); + } + return builder.build(); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/package-info.java b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/package-info.java new file mode 100644 index 00000000..b3113e97 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/codec/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014-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. + */ + +/** + * Implementations of the codec broker and built-in entity JSON codecs. + */ +package org.onosproject.codec.impl; 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 new file mode 100644 index 00000000..bdf7d732 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopology.java @@ -0,0 +1,502 @@ +/* + * Copyright 2014-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.common; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import com.google.common.collect.ImmutableMap; +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.GraphPathSearch; +import org.onlab.graph.GraphPathSearch.Result; +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.DefaultPath; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.net.topology.ClusterId; +import org.onosproject.net.topology.DefaultTopologyCluster; +import org.onosproject.net.topology.DefaultTopologyVertex; +import org.onosproject.net.topology.GraphDescription; +import org.onosproject.net.topology.LinkWeight; +import org.onosproject.net.topology.Topology; +import org.onosproject.net.topology.TopologyCluster; +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.List; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.MoreObjects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; +import static org.onlab.graph.GraphPathSearch.ALL_PATHS; +import static org.onlab.util.Tools.isNullOrEmpty; +import static org.onosproject.core.CoreService.CORE_PROVIDER_ID; +import static org.onosproject.net.Link.State.ACTIVE; +import static org.onosproject.net.Link.State.INACTIVE; +import static org.onosproject.net.Link.Type.INDIRECT; + +/** + * Default implementation of the topology descriptor. This carries the backing + * topology data. + */ +public class DefaultTopology extends AbstractModel implements Topology { + + private static final DijkstraGraphSearch DIJKSTRA = new DijkstraGraphSearch<>(); + private static final TarjanGraphSearch TARJAN = new TarjanGraphSearch<>(); + + private final long time; + private final long creationTime; + private final long computeCost; + private final TopologyGraph graph; + + private final LinkWeight weight; + private final Supplier> clusterResults; + private final Supplier> clusters; + private final Supplier> infrastructurePoints; + private final Supplier> broadcastSets; + private final Function broadcastFunction; + private final Supplier clusterIndexes; + + /** + * Creates a topology descriptor attributed to the specified provider. + * + * @param providerId identity of the provider + * @param description data describing the new topology + * @param broadcastFunction broadcast point function + */ + public DefaultTopology(ProviderId providerId, GraphDescription description, + Function broadcastFunction) { + super(providerId); + this.broadcastFunction = broadcastFunction; + this.time = description.timestamp(); + this.creationTime = description.creationTime(); + + // Build the graph + this.graph = new DefaultTopologyGraph(description.vertexes(), + description.edges()); + + this.clusterResults = Suppliers.memoize(() -> searchForClusters()); + this.clusters = Suppliers.memoize(() -> buildTopologyClusters()); + + this.clusterIndexes = Suppliers.memoize(() -> buildIndexes()); + + this.weight = new HopCountLinkWeight(graph.getVertexes().size()); + this.broadcastSets = Suppliers.memoize(() -> buildBroadcastSets()); + this.infrastructurePoints = Suppliers.memoize(() -> findInfrastructurePoints()); + this.computeCost = Math.max(0, System.nanoTime() - time); + } + + /** + * Creates a topology descriptor attributed to the specified provider. + * + * @param providerId identity of the provider + * @param description data describing the new topology + */ + public DefaultTopology(ProviderId providerId, GraphDescription description) { + this(providerId, description, null); + } + + @Override + public long time() { + return time; + } + + @Override + public long creationTime() { + return creationTime; + } + + @Override + public long computeCost() { + return computeCost; + } + + @Override + public int clusterCount() { + return clusters.get().size(); + } + + @Override + public int deviceCount() { + return graph.getVertexes().size(); + } + + @Override + public int linkCount() { + return graph.getEdges().size(); + } + + private ImmutableMap clustersByDevice() { + return clusterIndexes.get().clustersByDevice; + } + + private ImmutableSetMultimap devicesByCluster() { + return clusterIndexes.get().devicesByCluster; + } + + private ImmutableSetMultimap linksByCluster() { + return clusterIndexes.get().linksByCluster; + } + + /** + * Returns the backing topology graph. + * + * @return topology graph + */ + public TopologyGraph getGraph() { + return graph; + } + + /** + * Returns the set of topology clusters. + * + * @return set of clusters + */ + public Set getClusters() { + return ImmutableSet.copyOf(clusters.get().values()); + } + + /** + * Returns the specified topology cluster. + * + * @param clusterId cluster identifier + * @return topology cluster + */ + public TopologyCluster getCluster(ClusterId clusterId) { + return clusters.get().get(clusterId); + } + + /** + * Returns the topology cluster that contains the given device. + * + * @param deviceId device identifier + * @return topology cluster + */ + public TopologyCluster getCluster(DeviceId deviceId) { + return clustersByDevice().get(deviceId); + } + + /** + * Returns the set of cluster devices. + * + * @param cluster topology cluster + * @return cluster devices + */ + public Set getClusterDevices(TopologyCluster cluster) { + return devicesByCluster().get(cluster); + } + + /** + * Returns the set of cluster links. + * + * @param cluster topology cluster + * @return cluster links + */ + public Set getClusterLinks(TopologyCluster cluster) { + return linksByCluster().get(cluster); + } + + /** + * Indicates whether the given point is an infrastructure link end-point. + * + * @param connectPoint connection point + * @return true if infrastructure + */ + public boolean isInfrastructure(ConnectPoint connectPoint) { + return infrastructurePoints.get().contains(connectPoint); + } + + /** + * Indicates whether the given point is part of a broadcast set. + * + * @param connectPoint connection point + * @return true if in broadcast set + */ + public boolean isBroadcastPoint(ConnectPoint connectPoint) { + if (broadcastFunction != null) { + return broadcastFunction.apply(connectPoint); + } + + // Any non-infrastructure, i.e. edge points are assumed to be OK. + if (!isInfrastructure(connectPoint)) { + return true; + } + + // Find the cluster to which the device belongs. + TopologyCluster cluster = clustersByDevice().get(connectPoint.deviceId()); + checkArgument(cluster != null, "No cluster found for device %s", connectPoint.deviceId()); + + // If the broadcast set is null or empty, or if the point explicitly + // belongs to it, return true. + Set points = broadcastSets.get().get(cluster.id()); + return isNullOrEmpty(points) || points.contains(connectPoint); + } + + /** + * Returns the size of the cluster broadcast set. + * + * @param clusterId cluster identifier + * @return size of the cluster broadcast set + */ + public int broadcastSetSize(ClusterId clusterId) { + return broadcastSets.get().get(clusterId).size(); + } + + /** + * Returns the set of the cluster broadcast points. + * + * @param clusterId cluster identifier + * @return set of cluster broadcast points + */ + public Set broadcastPoints(ClusterId clusterId) { + return broadcastSets.get().get(clusterId); + } + + /** + * Returns the set of pre-computed shortest paths between source and + * destination devices. + * + * @param src source device + * @param dst destination device + * @return set of shortest paths + */ + public Set getPaths(DeviceId src, DeviceId dst) { + return getPaths(src, dst, null); + } + + /** + * Computes on-demand the set of shortest paths between source and + * destination devices. + * + * @param src source device + * @param dst destination device + * @param weight link weight function + * @return set of shortest paths + */ + public Set getPaths(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 = + DIJKSTRA.search(graph, srcV, dstV, weight, ALL_PATHS); + ImmutableSet.Builder builder = ImmutableSet.builder(); + for (org.onlab.graph.Path path : result.paths()) { + builder.add(networkPath(path)); + } + return builder.build(); + } + + // 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()); + } + return new DefaultPath(CORE_PROVIDER_ID, links, path.cost()); + } + + // Searches for SCC clusters in the network topology graph using Tarjan + // algorithm. + private SCCResult searchForClusters() { + return TARJAN.search(graph, new NoIndirectLinksWeight()); + } + + // Builds the topology clusters and returns the id-cluster bindings. + 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(); + List> clusterEdges = results.clusterEdges(); + + // Scan over the lists and create a cluster from the results. + for (int i = 0, n = results.clusterCount(); i < n; i++) { + Set vertexSet = clusterVertexes.get(i); + Set edgeSet = clusterEdges.get(i); + + ClusterId cid = ClusterId.clusterId(i); + DefaultTopologyCluster cluster = new DefaultTopologyCluster(cid, + vertexSet.size(), + edgeSet.size(), + findRoot(vertexSet)); + clusterBuilder.put(cid, cluster); + } + return clusterBuilder.build(); + } + + // Finds the vertex whose device id is the lexicographical minimum in the + // specified set. + private TopologyVertex findRoot(Set vertexSet) { + TopologyVertex minVertex = null; + for (TopologyVertex vertex : vertexSet) { + if ((minVertex == null) || (minVertex.deviceId() + .toString().compareTo(minVertex.deviceId().toString()) < 0)) { + minVertex = vertex; + } + } + return minVertex; + } + + // Processes a map of broadcast sets for each cluster. + private ImmutableSetMultimap buildBroadcastSets() { + Builder builder = ImmutableSetMultimap + .builder(); + for (TopologyCluster cluster : clusters.get().values()) { + addClusterBroadcastSet(cluster, builder); + } + return builder.build(); + } + + // Finds all broadcast points for the cluster. These are those connection + // points which lie along the shortest paths between the cluster root and + // all other devices within the cluster. + private void addClusterBroadcastSet(TopologyCluster cluster, Builder builder) { + // Use the graph root search results to build the broadcast set. + Result result = DIJKSTRA.search(graph, cluster.root(), null, weight, 1); + for (Map.Entry> entry : result.parents().entrySet()) { + TopologyVertex vertex = entry.getKey(); + + // Ignore any parents that lead outside the cluster. + if (clustersByDevice().get(vertex.deviceId()) != cluster) { + continue; + } + + // Ignore any back-link sets that are empty. + Set parents = entry.getValue(); + if (parents.isEmpty()) { + continue; + } + + // Use the first back-link source and destinations to add to the + // broadcast set. + Link link = parents.iterator().next().link(); + builder.put(cluster.id(), link.src()); + builder.put(cluster.id(), link.dst()); + } + } + + // Collects and returns an set of all infrastructure link end-points. + private ImmutableSet findInfrastructurePoints() { + ImmutableSet.Builder builder = ImmutableSet.builder(); + for (TopologyEdge edge : graph.getEdges()) { + builder.add(edge.link().src()); + builder.add(edge.link().dst()); + } + return builder.build(); + } + + // Builds cluster-devices, cluster-links and device-cluster indexes. + private ClusterIndexes buildIndexes() { + // Prepare the index builders + ImmutableMap.Builder clusterBuilder = + ImmutableMap.builder(); + ImmutableSetMultimap.Builder devicesBuilder = + ImmutableSetMultimap.builder(); + ImmutableSetMultimap.Builder linksBuilder = + ImmutableSetMultimap.builder(); + + // Now scan through all the clusters + for (TopologyCluster cluster : clusters.get().values()) { + int i = cluster.id().index(); + + // Scan through all the cluster vertexes. + for (TopologyVertex vertex : clusterResults.get().clusterVertexes().get(i)) { + devicesBuilder.put(cluster, vertex.deviceId()); + clusterBuilder.put(vertex.deviceId(), cluster); + } + + // Scan through all the cluster edges. + for (TopologyEdge edge : clusterResults.get().clusterEdges().get(i)) { + linksBuilder.put(cluster, edge.link()); + } + } + + // Finalize all indexes. + return new ClusterIndexes(clusterBuilder.build(), + devicesBuilder.build(), + linksBuilder.build()); + } + + // Link weight for measuring link cost as hop count with indirect links + // being as expensive as traversing the entire graph to assume the worst. + private static class HopCountLinkWeight implements LinkWeight { + private final int indirectLinkCost; + + HopCountLinkWeight(int indirectLinkCost) { + this.indirectLinkCost = indirectLinkCost; + } + + @Override + public double weight(TopologyEdge edge) { + // To force preference to use direct paths first, make indirect + // links as expensive as the linear vertex traversal. + return edge.link().state() == + ACTIVE ? (edge.link().type() == + INDIRECT ? indirectLinkCost : 1) : -1; + } + } + + // Link weight for preventing traversal over indirect links. + private static class NoIndirectLinksWeight implements LinkWeight { + @Override + public double weight(TopologyEdge edge) { + return (edge.link().state() == INACTIVE) + || (edge.link().type() == INDIRECT) ? -1 : 1; + } + } + + static final class ClusterIndexes { + final ImmutableMap clustersByDevice; + final ImmutableSetMultimap devicesByCluster; + final ImmutableSetMultimap linksByCluster; + + public ClusterIndexes(ImmutableMap clustersByDevice, + ImmutableSetMultimap devicesByCluster, + ImmutableSetMultimap linksByCluster) { + this.clustersByDevice = clustersByDevice; + this.devicesByCluster = devicesByCluster; + this.linksByCluster = linksByCluster; + } + } + + @Override + public String toString() { + return toStringHelper(this) + .add("time", time) + .add("creationTime", creationTime) + .add("computeCost", computeCost) + .add("clusters", clusterCount()) + .add("devices", deviceCount()) + .add("links", linkCount()).toString(); + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopologyGraph.java b/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopologyGraph.java new file mode 100644 index 00000000..b06065e7 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/common/DefaultTopologyGraph.java @@ -0,0 +1,43 @@ +/* + * Copyright 2014 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.common; + +import org.onlab.graph.AdjacencyListsGraph; +import org.onosproject.net.topology.TopologyEdge; +import org.onosproject.net.topology.TopologyGraph; +import org.onosproject.net.topology.TopologyVertex; + +import java.util.Set; + +/** + * Default implementation of an immutable topology graph based on a generic + * implementation of adjacency lists graph. + */ +public class DefaultTopologyGraph + extends AdjacencyListsGraph + implements TopologyGraph { + + /** + * Creates a topology graph comprising of the specified vertexes and edges. + * + * @param vertexes set of graph vertexes + * @param edges set of graph edges + */ + public DefaultTopologyGraph(Set vertexes, Set edges) { + super(vertexes, edges); + } + +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java b/framework/src/onos/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java new file mode 100644 index 00000000..54f0fb89 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java @@ -0,0 +1,432 @@ +/* + * 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.common.app; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.io.ByteStreams; +import com.google.common.io.Files; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.HierarchicalConfiguration; +import org.apache.commons.configuration.XMLConfiguration; +import org.onlab.util.Tools; +import org.onosproject.app.ApplicationDescription; +import org.onosproject.app.ApplicationEvent; +import org.onosproject.app.ApplicationException; +import org.onosproject.app.ApplicationStoreDelegate; +import org.onosproject.app.DefaultApplicationDescription; +import org.onosproject.core.ApplicationRole; +import org.onosproject.core.Version; +import org.onosproject.security.AppPermission; +import org.onosproject.security.Permission; +import org.onosproject.store.AbstractStore; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.nio.charset.Charset; +import java.nio.file.NoSuchFileException; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.io.ByteStreams.toByteArray; +import static com.google.common.io.Files.createParentDirs; +import static com.google.common.io.Files.write; + +/** + * Facility for reading application archive stream and managing application + * directory structure. + */ +public class ApplicationArchive + extends AbstractStore { + + private static Logger log = LoggerFactory.getLogger(ApplicationArchive.class); + + // Magic strings to search for at the beginning of the archive stream + private static final String XML_MAGIC = " getApplicationNames() { + ImmutableSet.Builder names = ImmutableSet.builder(); + File[] files = appsDir.listFiles(File::isDirectory); + if (files != null) { + for (File file : files) { + names.add(file.getName()); + } + } + return names.build(); + } + + /** + * Returns the timestamp in millis since start of epoch, of when the + * specified application was last modified or changed state. + * + * @param appName application name + * @return number of millis since start of epoch + */ + public long getUpdateTime(String appName) { + return appFile(appName, APP_XML).lastModified(); + } + + /** + * Loads the application descriptor from the specified application archive + * stream and saves the stream in the appropriate application archive + * directory. + * + * @param appName application name + * @return application descriptor + * @throws org.onosproject.app.ApplicationException if unable to read application description + */ + public ApplicationDescription getApplicationDescription(String appName) { + try { + XMLConfiguration cfg = new XMLConfiguration(); + cfg.setAttributeSplittingDisabled(true); + cfg.setDelimiterParsingDisabled(true); + cfg.load(appFile(appName, APP_XML)); + return loadAppDescription(cfg); + } catch (Exception e) { + throw new ApplicationException("Unable to get app description", e); + } + } + + /** + * Loads the application descriptor from the specified application archive + * stream and saves the stream in the appropriate application archive + * directory. + * + * @param stream application archive stream + * @return application descriptor + * @throws org.onosproject.app.ApplicationException if unable to read the + * archive stream or store + * the application archive + */ + public synchronized ApplicationDescription saveApplication(InputStream stream) { + try (InputStream ais = stream) { + byte[] cache = toByteArray(ais); + InputStream bis = new ByteArrayInputStream(cache); + + boolean plainXml = isPlainXml(cache); + ApplicationDescription desc = plainXml ? + parsePlainAppDescription(bis) : parseZippedAppDescription(bis); + checkState(!appFile(desc.name(), APP_XML).exists(), + "Application %s already installed", desc.name()); + + if (plainXml) { + expandPlainApplication(cache, desc); + } else { + bis.reset(); + expandZippedApplication(bis, desc); + + bis.reset(); + saveApplication(bis, desc); + } + + installArtifacts(desc); + return desc; + } catch (IOException e) { + throw new ApplicationException("Unable to save application", e); + } + } + + // Indicates whether the stream encoded in the given bytes is plain XML. + private boolean isPlainXml(byte[] bytes) { + return substring(bytes, XML_MAGIC.length()).equals(XML_MAGIC) || + substring(bytes, APP_MAGIC_DEPTH).contains(APP_MAGIC); + } + + // Returns the substring of maximum possible length from the specified bytes. + private String substring(byte[] bytes, int length) { + return new String(bytes, 0, Math.min(bytes.length, length), Charset.forName("UTF-8")); + } + + /** + * Purges the application archive directory. + * + * @param appName application name + */ + public synchronized void purgeApplication(String appName) { + File appDir = new File(appsDir, appName); + try { + Tools.removeDirectory(appDir); + } catch (IOException e) { + throw new ApplicationException("Unable to purge application " + appName, e); + } + if (appDir.exists()) { + throw new ApplicationException("Unable to purge application " + appName); + } + } + + /** + * Returns application archive stream for the specified application. This + * will be either the application ZIP file or the application XML file. + * + * @param appName application name + * @return application archive stream + */ + public synchronized InputStream getApplicationInputStream(String appName) { + try { + File appFile = appFile(appName, appName + OAR); + return new FileInputStream(appFile.exists() ? appFile : appFile(appName, APP_XML)); + } catch (FileNotFoundException e) { + throw new ApplicationException("Application " + appName + " not found"); + } + } + + // Scans the specified ZIP stream for app.xml entry and parses it producing + // an application descriptor. + private ApplicationDescription parseZippedAppDescription(InputStream stream) + throws IOException { + try (ZipInputStream zis = new ZipInputStream(stream)) { + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + if (entry.getName().equals(APP_XML)) { + byte[] data = ByteStreams.toByteArray(zis); + return parsePlainAppDescription(new ByteArrayInputStream(data)); + } + zis.closeEntry(); + } + } + throw new IOException("Unable to locate " + APP_XML); + } + + // Scans the specified XML stream and parses it producing an application descriptor. + private ApplicationDescription parsePlainAppDescription(InputStream stream) + throws IOException { + XMLConfiguration cfg = new XMLConfiguration(); + cfg.setAttributeSplittingDisabled(true); + cfg.setDelimiterParsingDisabled(true); + try { + cfg.load(stream); + return loadAppDescription(cfg); + } catch (ConfigurationException e) { + throw new IOException("Unable to parse " + APP_XML, e); + } + } + + private ApplicationDescription loadAppDescription(XMLConfiguration cfg) { + String name = cfg.getString(NAME); + Version version = Version.version(cfg.getString(VERSION)); + String desc = cfg.getString(DESCRIPTION); + String origin = cfg.getString(ORIGIN); + ApplicationRole role = getRole(cfg.getString(ROLE)); + Set perms = getPermissions(cfg); + String featRepo = cfg.getString(FEATURES_REPO); + URI featuresRepo = featRepo != null ? URI.create(featRepo) : null; + List features = ImmutableList.copyOf(cfg.getString(FEATURES).split(",")); + + return new DefaultApplicationDescription(name, version, desc, origin, role, + perms, featuresRepo, features); + } + + // Expands the specified ZIP stream into app-specific directory. + private void expandZippedApplication(InputStream stream, ApplicationDescription desc) + throws IOException { + ZipInputStream zis = new ZipInputStream(stream); + ZipEntry entry; + File appDir = new File(appsDir, desc.name()); + while ((entry = zis.getNextEntry()) != null) { + if (!entry.isDirectory()) { + byte[] data = ByteStreams.toByteArray(zis); + zis.closeEntry(); + File file = new File(appDir, entry.getName()); + createParentDirs(file); + write(data, file); + } + } + zis.close(); + } + + // Saves the specified XML stream into app-specific directory. + private void expandPlainApplication(byte[] stream, ApplicationDescription desc) + throws IOException { + File file = appFile(desc.name(), APP_XML); + checkState(!file.getParentFile().exists(), "Application already installed"); + createParentDirs(file); + write(stream, file); + } + + + // Saves the specified ZIP stream into a file under app-specific directory. + private void saveApplication(InputStream stream, ApplicationDescription desc) + throws IOException { + Files.write(toByteArray(stream), appFile(desc.name(), desc.name() + OAR)); + } + + // Installs application artifacts into M2 repository. + private void installArtifacts(ApplicationDescription desc) throws IOException { + try { + Tools.copyDirectory(appFile(desc.name(), M2_PREFIX), m2Dir); + } catch (NoSuchFileException e) { + log.debug("Application {} has no M2 artifacts", desc.name()); + } + } + + /** + * Marks the app as active by creating token file in the app directory. + * + * @param appName application name + * @return true if file was created + */ + protected boolean setActive(String appName) { + try { + return appFile(appName, "active").createNewFile() && updateTime(appName); + } catch (IOException e) { + throw new ApplicationException("Unable to mark app as active", e); + } + } + + /** + * Clears the app as active by deleting token file in the app directory. + * + * @param appName application name + * @return true if file was deleted + */ + protected boolean clearActive(String appName) { + return appFile(appName, "active").delete() && updateTime(appName); + } + + /** + * Updates the time-stamp of the app descriptor file. + * + * @param appName application name + * @return true if the app descriptor was updated + */ + protected boolean updateTime(String appName) { + return appFile(appName, APP_XML).setLastModified(System.currentTimeMillis()); + } + + /** + * Indicates whether the app was marked as active by checking for token file. + * + * @param appName application name + * @return true if the app is marked as active + */ + protected boolean isActive(String appName) { + return appFile(appName, "active").exists(); + } + + + // Returns the name of the file located under the specified app directory. + private File appFile(String appName, String fileName) { + return new File(new File(appsDir, appName), fileName); + } + + // Returns the set of Permissions specified in the app.xml file + private ImmutableSet getPermissions(XMLConfiguration cfg) { + List permissionList = new ArrayList(); + + for (Object o : cfg.getList(APP_PERMISSIONS)) { + String name = (String) o; + permissionList.add(new Permission(AppPermission.class.getName(), name)); + } + for (Object o : cfg.getList(NET_PERMISSIONS)) { + //TODO: TO BE FLESHED OUT WHEN NETWORK PERMISSIONS ARE SUPPORTED + break; + } + + List fields = + cfg.configurationsAt(JAVA_PERMISSIONS); + for (HierarchicalConfiguration sub : fields) { + String classname = sub.getString("classname"); + String name = sub.getString("name"); + String actions = sub.getString("actions"); + + if (classname != null && name != null) { + permissionList.add(new Permission(classname, name, actions)); + } + } + return ImmutableSet.copyOf(permissionList); + } + + // + // Returns application role type + public ApplicationRole getRole(String value) { + if (value == null) { + return ApplicationRole.UNSPECIFIED; + } else { + try { + return ApplicationRole.valueOf(value.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { + log.debug("Unknown role value: %s", value); + return ApplicationRole.UNSPECIFIED; + } + } + } +} diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/common/app/package-info.java b/framework/src/onos/core/common/src/main/java/org/onosproject/common/app/package-info.java new file mode 100644 index 00000000..898bad7b --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/common/app/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. + */ + +/** + * Common facilities for construction of application management subsystem. + */ +package org.onosproject.common.app; \ No newline at end of file diff --git a/framework/src/onos/core/common/src/main/java/org/onosproject/common/package-info.java b/framework/src/onos/core/common/src/main/java/org/onosproject/common/package-info.java new file mode 100644 index 00000000..8cd9b8c4 --- /dev/null +++ b/framework/src/onos/core/common/src/main/java/org/onosproject/common/package-info.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +/** + * Miscellaneous common facilities used for construction of various core and + * app subsystems. + */ +package org.onosproject.common; \ No newline at end of file diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ConnectPointJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ConnectPointJsonMatcher.java new file mode 100644 index 00000000..8d85751e --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ConnectPointJsonMatcher.java @@ -0,0 +1,71 @@ +/* + * 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.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.net.ConnectPoint; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Hamcrest matcher for connect points. + */ + +public final class ConnectPointJsonMatcher extends TypeSafeDiagnosingMatcher { + + private final ConnectPoint connectPoint; + + private ConnectPointJsonMatcher(ConnectPoint connectPointValue) { + connectPoint = connectPointValue; + } + + @Override + public boolean matchesSafely(JsonNode jsonConnectPoint, Description description) { + // check device + final String jsonDevice = jsonConnectPoint.get("device").asText(); + final String device = connectPoint.deviceId().toString(); + if (!jsonDevice.equals(device)) { + description.appendText("device was " + jsonDevice); + return false; + } + + // check port + final String jsonPort = jsonConnectPoint.get("port").asText(); + final String port = connectPoint.port().toString(); + if (!jsonPort.equals(port)) { + description.appendText("port was " + jsonPort); + return false; + } + + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText(connectPoint.toString()); + } + + /** + * Factory to allocate an connect point matcher. + * + * @param connectPoint connect point object we are looking for + * @return matcher + */ + public static ConnectPointJsonMatcher matchesConnectPoint(ConnectPoint connectPoint) { + return new ConnectPointJsonMatcher(connectPoint); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ConstraintCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ConstraintCodecTest.java new file mode 100644 index 00000000..2a47d115 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ConstraintCodecTest.java @@ -0,0 +1,202 @@ +/* + * 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 java.io.IOException; +import java.io.InputStream; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.codec.JsonCodec; +import org.onosproject.core.CoreService; +import org.onosproject.net.Link; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.constraint.AnnotationConstraint; +import org.onosproject.net.intent.constraint.AsymmetricPathConstraint; +import org.onosproject.net.intent.constraint.BandwidthConstraint; +import org.onosproject.net.intent.constraint.LambdaConstraint; +import org.onosproject.net.intent.constraint.LatencyConstraint; +import org.onosproject.net.intent.constraint.LinkTypeConstraint; +import org.onosproject.net.intent.constraint.ObstacleConstraint; +import org.onosproject.net.intent.constraint.WaypointConstraint; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.net.NetTestTools.APP_ID; +import static org.onosproject.net.NetTestTools.did; + +/** + * Unit tests for Constraint codec. + */ +public class ConstraintCodecTest { + + MockCodecContext context; + JsonCodec constraintCodec; + final CoreService mockCoreService = createMock(CoreService.class); + + /** + * Sets up for each test. Creates a context and fetches the flow rule + * codec. + */ + @Before + public void setUp() { + context = new MockCodecContext(); + constraintCodec = context.codec(Constraint.class); + assertThat(constraintCodec, notNullValue()); + + expect(mockCoreService.registerApplication(FlowRuleCodec.REST_APP_ID)) + .andReturn(APP_ID).anyTimes(); + replay(mockCoreService); + context.registerService(CoreService.class, mockCoreService); + } + + /** + * Reads in a constraint from the given resource and decodes it. + * + * @param resourceName resource to use to read the JSON for the constraint + * @return decoded constraint + */ + private Constraint getConstraint(String resourceName) { + InputStream jsonStream = ConstraintCodecTest.class + .getResourceAsStream(resourceName); + try { + JsonNode json = context.mapper().readTree(jsonStream); + assertThat(json, notNullValue()); + Constraint constraint = constraintCodec.decode((ObjectNode) json, context); + assertThat(constraint, notNullValue()); + return checkNotNull(constraint); + } catch (IOException ioe) { + Assert.fail(ioe.getMessage()); + throw new IllegalStateException("cannot happen"); + } + } + + + /** + * Tests link type constraint. + */ + @Test + public void linkTypeConstraint() { + Constraint constraint = getConstraint("LinkTypeConstraint.json"); + assertThat(constraint, instanceOf(LinkTypeConstraint.class)); + + LinkTypeConstraint linkTypeConstraint = (LinkTypeConstraint) constraint; + assertThat(linkTypeConstraint.isInclusive(), is(false)); + assertThat(linkTypeConstraint.types(), hasSize(2)); + assertThat(linkTypeConstraint.types(), hasItem(Link.Type.OPTICAL)); + assertThat(linkTypeConstraint.types(), hasItem(Link.Type.DIRECT)); + } + + /** + * Tests annotation constraint. + */ + @Test + public void annotationConstraint() { + Constraint constraint = getConstraint("AnnotationConstraint.json"); + assertThat(constraint, instanceOf(AnnotationConstraint.class)); + + AnnotationConstraint annotationConstraint = (AnnotationConstraint) constraint; + assertThat(annotationConstraint.key(), is("key")); + assertThat(annotationConstraint.threshold(), is(123.0D)); + } + + /** + * Tests bandwidth constraint. + */ + @Test + public void bandwidthConstraint() { + Constraint constraint = getConstraint("BandwidthConstraint.json"); + assertThat(constraint, instanceOf(BandwidthConstraint.class)); + + BandwidthConstraint bandwidthConstraint = (BandwidthConstraint) constraint; + assertThat(bandwidthConstraint.bandwidth().toDouble(), is(345.678D)); + } + + /** + * Tests lambda constraint. + */ + @Test + public void lambdaConstraint() { + Constraint constraint = getConstraint("LambdaConstraint.json"); + assertThat(constraint, instanceOf(LambdaConstraint.class)); + + LambdaConstraint lambdaConstraint = (LambdaConstraint) constraint; + assertThat(lambdaConstraint.lambda().toInt(), is(444)); + } + + /** + * Tests latency constraint. + */ + @Test + public void latencyConstraint() { + Constraint constraint = getConstraint("LatencyConstraint.json"); + assertThat(constraint, instanceOf(LatencyConstraint.class)); + + LatencyConstraint latencyConstraint = (LatencyConstraint) constraint; + assertThat(latencyConstraint.latency().toMillis(), is(111L)); + } + + /** + * Tests obstacle constraint. + */ + @Test + public void obstacleConstraint() { + Constraint constraint = getConstraint("ObstacleConstraint.json"); + assertThat(constraint, instanceOf(ObstacleConstraint.class)); + + ObstacleConstraint obstacleConstraint = (ObstacleConstraint) constraint; + + assertThat(obstacleConstraint.obstacles(), hasItem(did("dev1"))); + assertThat(obstacleConstraint.obstacles(), hasItem(did("dev2"))); + assertThat(obstacleConstraint.obstacles(), hasItem(did("dev3"))); + } + + /** + * Tests waypoint constaint. + */ + @Test + public void waypointConstraint() { + Constraint constraint = getConstraint("WaypointConstraint.json"); + assertThat(constraint, instanceOf(WaypointConstraint.class)); + + WaypointConstraint waypointConstraint = (WaypointConstraint) constraint; + + assertThat(waypointConstraint.waypoints(), hasItem(did("devA"))); + assertThat(waypointConstraint.waypoints(), hasItem(did("devB"))); + assertThat(waypointConstraint.waypoints(), hasItem(did("devC"))); + } + + /** + * Tests asymmetric path constraint. + */ + @Test + public void asymmetricPathConstraint() { + Constraint constraint = getConstraint("AsymmetricPathConstraint.json"); + assertThat(constraint, instanceOf(AsymmetricPathConstraint.class)); + } +} 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 new file mode 100644 index 00000000..6bf46803 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java @@ -0,0 +1,445 @@ +/* + * 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 java.util.EnumMap; + +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.Ip6Address; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.TpPort; +import org.onlab.packet.VlanId; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.GridType; +import org.onosproject.net.Lambda; +import org.onosproject.net.OchSignalType; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.criteria.Criteria; +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; + +/** + * Unit tests for criterion codec. + */ +public class CriterionCodecTest { + + CodecContext context; + JsonCodec criterionCodec; + final PortNumber port = PortNumber.portNumber(1); + final IpPrefix ipPrefix4 = IpPrefix.valueOf("10.1.1.0/24"); + final IpPrefix ipPrefix6 = IpPrefix.valueOf("fe80::/64"); + final MacAddress mac1 = MacAddress.valueOf("00:00:11:00:00:01"); + final TpPort tpPort = TpPort.tpPort(40000); + + /** + * Sets up for each test. Creates a context and fetches the criterion + * codec. + */ + @Before + public void setUp() { + context = new MockCodecContext(); + criterionCodec = context.codec(Criterion.class); + assertThat(criterionCodec, notNullValue()); + } + + + /** + * Checks that all criterion types are covered by the codec. + */ + @Test + public void checkCriterionTypes() throws Exception { + EncodeCriterionCodecHelper encoder = new EncodeCriterionCodecHelper( + Criteria.dummy(), context); + EnumMap formatMap = + getField(encoder, "formatMap"); + assertThat(formatMap, notNullValue()); + + for (Criterion.Type type : Criterion.Type.values()) { + assertThat("Entry not found for " + type.toString(), + formatMap.get(type), notNullValue()); + } + } + + /** + * Tests in port criterion. + */ + @Test + public void matchInPortTest() { + Criterion criterion = Criteria.matchInPort(port); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests in physical port criterion. + */ + @Test + public void matchInPhyPortTest() { + Criterion criterion = Criteria.matchInPhyPort(port); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests metadata criterion. + */ + @Test + public void matchMetadataTest() { + Criterion criterion = Criteria.matchMetadata(0xabcdL); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests ethernet destination criterion. + */ + @Test + public void matchEthDstTest() { + Criterion criterion = Criteria.matchEthDst(mac1); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests ethernet source criterion. + */ + @Test + public void matchEthSrcTest() { + Criterion criterion = Criteria.matchEthSrc(mac1); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests ethernet type criterion. + */ + @Test + public void matchEthTypeTest() { + Criterion criterion = Criteria.matchEthType((short) 0x8844); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests VLAN Id criterion. + */ + @Test + public void matchVlanIdTest() { + Criterion criterion = Criteria.matchVlanId(VlanId.ANY); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests VLAN PCP criterion. + */ + @Test + public void matchVlanPcpTest() { + Criterion criterion = Criteria.matchVlanPcp((byte) 7); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IP DSCP criterion. + */ + @Test + public void matchIPDscpTest() { + Criterion criterion = Criteria.matchIPDscp((byte) 63); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IP ECN criterion. + */ + @Test + public void matchIPEcnTest() { + Criterion criterion = Criteria.matchIPEcn((byte) 3); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IP protocol criterion. + */ + @Test + public void matchIPProtocolTest() { + Criterion criterion = Criteria.matchIPProtocol((byte) 250); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IP source criterion. + */ + @Test + public void matchIPSrcTest() { + Criterion criterion = Criteria.matchIPSrc(ipPrefix4); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IP destination criterion. + */ + @Test + public void matchIPDstTest() { + Criterion criterion = Criteria.matchIPDst(ipPrefix4); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests source TCP port criterion. + */ + @Test + public void matchTcpSrcTest() { + Criterion criterion = Criteria.matchTcpSrc(tpPort); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests destination TCP port criterion. + */ + @Test + public void matchTcpDstTest() { + Criterion criterion = Criteria.matchTcpDst(tpPort); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests source UDP port criterion. + */ + @Test + public void matchUdpSrcTest() { + Criterion criterion = Criteria.matchUdpSrc(tpPort); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests destination UDP criterion. + */ + @Test + public void matchUdpDstTest() { + Criterion criterion = Criteria.matchUdpDst(tpPort); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests source SCTP criterion. + */ + @Test + public void matchSctpSrcTest() { + Criterion criterion = Criteria.matchSctpSrc(tpPort); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests destination SCTP criterion. + */ + @Test + public void matchSctpDstTest() { + Criterion criterion = Criteria.matchSctpDst(tpPort); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests ICMP type criterion. + */ + @Test + public void matchIcmpTypeTest() { + Criterion criterion = Criteria.matchIcmpType((byte) 250); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests ICMP code criterion. + */ + @Test + public void matchIcmpCodeTest() { + Criterion criterion = Criteria.matchIcmpCode((byte) 250); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IPv6 source criterion. + */ + @Test + public void matchIPv6SrcTest() { + Criterion criterion = Criteria.matchIPv6Src(ipPrefix6); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IPv6 destination criterion. + */ + @Test + public void matchIPv6DstTest() { + Criterion criterion = Criteria.matchIPv6Dst(ipPrefix6); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IPv6 flow label criterion. + */ + @Test + public void matchIPv6FlowLabelTest() { + Criterion criterion = Criteria.matchIPv6FlowLabel(0xffffe); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests ICMP v6 type criterion. + */ + @Test + public void matchIcmpv6TypeTest() { + Criterion criterion = Criteria.matchIcmpv6Type((byte) 250); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests ICMP v6 code criterion. + */ + @Test + public void matchIcmpv6CodeTest() { + Criterion criterion = Criteria.matchIcmpv6Code((byte) 250); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IPV6 target address criterion. + */ + @Test + public void matchIPv6NDTargetAddressTest() { + Criterion criterion = + Criteria.matchIPv6NDTargetAddress( + Ip6Address.valueOf("1111:2222::")); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IPV6 SLL criterion. + */ + @Test + public void matchIPv6NDSourceLinkLayerAddressTest() { + Criterion criterion = Criteria.matchIPv6NDSourceLinkLayerAddress(mac1); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IPV6 TLL criterion. + */ + @Test + public void matchIPv6NDTargetLinkLayerAddressTest() { + Criterion criterion = Criteria.matchIPv6NDTargetLinkLayerAddress(mac1); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests MPLS label criterion. + */ + @Test + public void matchMplsLabelTest() { + Criterion criterion = Criteria.matchMplsLabel(MplsLabel.mplsLabel(0xffffe)); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests IPv6 Extension Header pseudo-field flags criterion. + */ + @Test + public void matchIPv6ExthdrFlagsTest() { + int exthdrFlags = + Criterion.IPv6ExthdrFlags.NONEXT.getValue() | + Criterion.IPv6ExthdrFlags.ESP.getValue() | + Criterion.IPv6ExthdrFlags.AUTH.getValue() | + Criterion.IPv6ExthdrFlags.DEST.getValue() | + Criterion.IPv6ExthdrFlags.FRAG.getValue() | + Criterion.IPv6ExthdrFlags.ROUTER.getValue() | + Criterion.IPv6ExthdrFlags.HOP.getValue() | + Criterion.IPv6ExthdrFlags.UNREP.getValue() | + Criterion.IPv6ExthdrFlags.UNSEQ.getValue(); + Criterion criterion = Criteria.matchIPv6ExthdrFlags(exthdrFlags); + ObjectNode result = criterionCodec.encode(criterion, context); + + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests lambda criterion. + */ + @Test + public void matchOchSignal() { + Lambda ochSignal = Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, 4, 8); + Criterion criterion = Criteria.matchLambda(ochSignal); + ObjectNode result = criterionCodec.encode(criterion, context); + assertThat(result, matchesCriterion(criterion)); + } + + /** + * Tests Och signal type criterion. + */ + @Test + public void matchOchSignalTypeTest() { + Criterion criterion = Criteria.matchOchSignalType(OchSignalType.FIXED_GRID); + 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/CriterionJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java new file mode 100644 index 00000000..bb3acad5 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java @@ -0,0 +1,609 @@ +/* + * 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 com.google.common.base.Joiner; +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.net.OchSignal; +import org.onosproject.net.flow.criteria.Criterion; + +import com.fasterxml.jackson.databind.JsonNode; +import org.onosproject.net.flow.criteria.EthCriterion; +import org.onosproject.net.flow.criteria.EthTypeCriterion; +import org.onosproject.net.flow.criteria.IPCriterion; +import org.onosproject.net.flow.criteria.IPDscpCriterion; +import org.onosproject.net.flow.criteria.IPEcnCriterion; +import org.onosproject.net.flow.criteria.IPProtocolCriterion; +import org.onosproject.net.flow.criteria.IPv6ExthdrFlagsCriterion; +import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion; +import org.onosproject.net.flow.criteria.IPv6NDLinkLayerAddressCriterion; +import org.onosproject.net.flow.criteria.IPv6NDTargetAddressCriterion; +import org.onosproject.net.flow.criteria.IcmpCodeCriterion; +import org.onosproject.net.flow.criteria.IcmpTypeCriterion; +import org.onosproject.net.flow.criteria.Icmpv6CodeCriterion; +import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion; +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.PortCriterion; +import org.onosproject.net.flow.criteria.SctpPortCriterion; +import org.onosproject.net.flow.criteria.TcpPortCriterion; +import org.onosproject.net.flow.criteria.UdpPortCriterion; +import org.onosproject.net.flow.criteria.VlanIdCriterion; +import org.onosproject.net.flow.criteria.VlanPcpCriterion; + +import java.util.Objects; + +/** + * Hamcrest matcher for criterion objects. + */ +public final class CriterionJsonMatcher extends + TypeSafeDiagnosingMatcher { + + final Criterion criterion; + Description description; + JsonNode jsonCriterion; + + /** + * Constructs a matcher object. + * + * @param criterionValue criterion to match + */ + private CriterionJsonMatcher(Criterion criterionValue) { + criterion = criterionValue; + } + + /** + * Factory to allocate an criterion matcher. + * + * @param criterion criterion object we are looking for + * @return matcher + */ + public static CriterionJsonMatcher matchesCriterion(Criterion criterion) { + return new CriterionJsonMatcher(criterion); + } + + /** + * Matches a port criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(PortCriterion criterion) { + final long port = criterion.port().toLong(); + final long jsonPort = jsonCriterion.get("port").asLong(); + if (port != jsonPort) { + description.appendText("port was " + Long.toString(jsonPort)); + return false; + } + return true; + } + + /** + * Matches a metadata criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(MetadataCriterion criterion) { + final long metadata = criterion.metadata(); + final long jsonMetadata = jsonCriterion.get("metadata").asLong(); + if (metadata != jsonMetadata) { + description.appendText("metadata was " + + Long.toString(jsonMetadata)); + return false; + } + return true; + } + + /** + * Matches an eth criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(EthCriterion criterion) { + final String mac = criterion.mac().toString(); + final String jsonMac = jsonCriterion.get("mac").textValue(); + if (!mac.equals(jsonMac)) { + description.appendText("mac was " + jsonMac); + return false; + } + return true; + } + + /** + * Matches an eth type criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(EthTypeCriterion criterion) { + final int ethType = criterion.ethType().toShort(); + final int jsonEthType = jsonCriterion.get("ethType").intValue(); + if (ethType != jsonEthType) { + description.appendText("ethType was " + + Integer.toString(jsonEthType)); + return false; + } + return true; + } + + /** + * Matches a VLAN ID criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(VlanIdCriterion criterion) { + final short vlanId = criterion.vlanId().toShort(); + final short jsonVlanId = jsonCriterion.get("vlanId").shortValue(); + if (vlanId != jsonVlanId) { + description.appendText("vlanId was " + Short.toString(jsonVlanId)); + return false; + } + return true; + } + + /** + * Matches a VLAN PCP criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(VlanPcpCriterion criterion) { + final byte priority = criterion.priority(); + final byte jsonPriority = + (byte) jsonCriterion.get("priority").shortValue(); + if (priority != jsonPriority) { + description.appendText("priority was " + Byte.toString(jsonPriority)); + return false; + } + return true; + } + + /** + * Matches an IP DSCP criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPDscpCriterion criterion) { + final byte ipDscp = criterion.ipDscp(); + final byte jsonIpDscp = (byte) jsonCriterion.get("ipDscp").shortValue(); + if (ipDscp != jsonIpDscp) { + description.appendText("IP DSCP was " + Byte.toString(jsonIpDscp)); + return false; + } + return true; + } + + /** + * Matches an IP ECN criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPEcnCriterion criterion) { + final byte ipEcn = criterion.ipEcn(); + final byte jsonIpEcn = (byte) jsonCriterion.get("ipEcn").shortValue(); + if (ipEcn != jsonIpEcn) { + description.appendText("IP ECN was " + Byte.toString(jsonIpEcn)); + return false; + } + return true; + } + + /** + * Matches an IP protocol criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPProtocolCriterion criterion) { + final short protocol = criterion.protocol(); + final short jsonProtocol = jsonCriterion.get("protocol").shortValue(); + if (protocol != jsonProtocol) { + description.appendText("protocol was " + + Short.toString(jsonProtocol)); + return false; + } + return true; + } + + /** + * Matches an IP address criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPCriterion criterion) { + final String ip = criterion.ip().toString(); + final String jsonIp = jsonCriterion.get("ip").textValue(); + if (!ip.equals(jsonIp)) { + description.appendText("ip was " + jsonIp); + return false; + } + return true; + } + + /** + * Matches a TCP port criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(TcpPortCriterion criterion) { + final int tcpPort = criterion.tcpPort().toInt(); + final int jsonTcpPort = jsonCriterion.get("tcpPort").intValue(); + if (tcpPort != jsonTcpPort) { + description.appendText("tcp port was " + + Integer.toString(jsonTcpPort)); + return false; + } + return true; + } + + /** + * Matches a UDP port criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(UdpPortCriterion criterion) { + final int udpPort = criterion.udpPort().toInt(); + final int jsonUdpPort = jsonCriterion.get("udpPort").intValue(); + if (udpPort != jsonUdpPort) { + description.appendText("udp port was " + + Integer.toString(jsonUdpPort)); + return false; + } + return true; + } + + /** + * Matches an SCTP port criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(SctpPortCriterion criterion) { + final int sctpPort = criterion.sctpPort().toInt(); + final int jsonSctpPort = jsonCriterion.get("sctpPort").intValue(); + if (sctpPort != jsonSctpPort) { + description.appendText("sctp port was " + + Integer.toString(jsonSctpPort)); + return false; + } + return true; + } + + /** + * Matches an ICMP type criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IcmpTypeCriterion criterion) { + final short icmpType = criterion.icmpType(); + final short jsonIcmpType = jsonCriterion.get("icmpType").shortValue(); + if (icmpType != jsonIcmpType) { + description.appendText("icmp type was " + + Short.toString(jsonIcmpType)); + return false; + } + return true; + } + + /** + * Matches an ICMP code criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IcmpCodeCriterion criterion) { + final short icmpCode = criterion.icmpCode(); + final short jsonIcmpCode = jsonCriterion.get("icmpCode").shortValue(); + if (icmpCode != jsonIcmpCode) { + description.appendText("icmp code was " + + Short.toString(jsonIcmpCode)); + return false; + } + return true; + } + + /** + * Matches an IPV6 flow label criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPv6FlowLabelCriterion criterion) { + final int flowLabel = criterion.flowLabel(); + final int jsonFlowLabel = jsonCriterion.get("flowLabel").intValue(); + if (flowLabel != jsonFlowLabel) { + description.appendText("IPv6 flow label was " + + Integer.toString(jsonFlowLabel)); + return false; + } + return true; + } + + /** + * Matches an ICMP V6 type criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(Icmpv6TypeCriterion criterion) { + final short icmpv6Type = criterion.icmpv6Type(); + final short jsonIcmpv6Type = + jsonCriterion.get("icmpv6Type").shortValue(); + if (icmpv6Type != jsonIcmpv6Type) { + description.appendText("icmpv6 type was " + + Short.toString(jsonIcmpv6Type)); + return false; + } + return true; + } + + /** + * Matches an IPV6 code criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(Icmpv6CodeCriterion criterion) { + final short icmpv6Code = criterion.icmpv6Code(); + final short jsonIcmpv6Code = + jsonCriterion.get("icmpv6Code").shortValue(); + if (icmpv6Code != jsonIcmpv6Code) { + description.appendText("icmpv6 code was " + + Short.toString(jsonIcmpv6Code)); + return false; + } + return true; + } + + /** + * Matches an IPV6 ND target criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPv6NDTargetAddressCriterion criterion) { + final String targetAddress = + criterion.targetAddress().toString(); + final String jsonTargetAddress = + jsonCriterion.get("targetAddress").textValue(); + if (!targetAddress.equals(jsonTargetAddress)) { + description.appendText("target address was " + + jsonTargetAddress); + return false; + } + return true; + } + + /** + * Matches an IPV6 ND link layer criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPv6NDLinkLayerAddressCriterion criterion) { + final String llAddress = + criterion.mac().toString(); + final String jsonLlAddress = + jsonCriterion.get("mac").textValue(); + if (!llAddress.equals(jsonLlAddress)) { + description.appendText("mac was " + jsonLlAddress); + return false; + } + return true; + } + + /** + * Matches an MPLS label criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(MplsCriterion criterion) { + final int label = criterion.label().toInt(); + final int jsonLabel = jsonCriterion.get("label").intValue(); + if (label != jsonLabel) { + description.appendText("label was " + Integer.toString(jsonLabel)); + return false; + } + return true; + } + + /** + * Matches an IPV6 exthdr criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(IPv6ExthdrFlagsCriterion criterion) { + final int exthdrFlags = criterion.exthdrFlags(); + final int jsonExthdrFlags = + jsonCriterion.get("exthdrFlags").intValue(); + if (exthdrFlags != jsonExthdrFlags) { + description.appendText("exthdrFlags was " + + Long.toHexString(jsonExthdrFlags)); + return false; + } + return true; + } + + /** + * Matches an Och signal criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(OchSignalCriterion criterion) { + final OchSignal ochSignal = criterion.lambda(); + final JsonNode jsonOchSignal = jsonCriterion.get("ochSignalId"); + String jsonGridType = jsonOchSignal.get("gridType").textValue(); + String jsonChannelSpacing = jsonOchSignal.get("channelSpacing").textValue(); + int jsonSpacingMultiplier = jsonOchSignal.get("spacingMultiplier").intValue(); + int jsonSlotGranularity = jsonOchSignal.get("slotGranularity").intValue(); + + boolean equality = Objects.equals(ochSignal.gridType().name(), jsonGridType) + && Objects.equals(ochSignal.channelSpacing().name(), jsonChannelSpacing) + && Objects.equals(ochSignal.spacingMultiplier(), jsonSpacingMultiplier) + && Objects.equals(ochSignal.slotGranularity(), jsonSlotGranularity); + + if (!equality) { + String joined = Joiner.on(", ") + .join(jsonGridType, jsonChannelSpacing, jsonSpacingMultiplier, jsonSlotGranularity); + + description.appendText("och signal id was " + joined); + return false; + } + return true; + } + + /** + * Matches an Och signal type criterion object. + * + * @param criterion criterion to match + * @return true if the JSON matches the criterion, false otherwise. + */ + private boolean matchCriterion(OchSignalTypeCriterion criterion) { + final String signalType = criterion.signalType().name(); + final String jsonSignalType = jsonCriterion.get("ochSignalType").textValue(); + if (!signalType.equals(jsonSignalType)) { + description.appendText("signal type was " + jsonSignalType); + return false; + } + return true; + } + + @Override + public boolean matchesSafely(JsonNode jsonCriterion, + Description description) { + this.description = description; + this.jsonCriterion = jsonCriterion; + final String type = criterion.type().name(); + final String jsonType = jsonCriterion.get("type").asText(); + if (!type.equals(jsonType)) { + description.appendText("type was " + type); + return false; + } + + switch (criterion.type()) { + + case IN_PORT: + case IN_PHY_PORT: + return matchCriterion((PortCriterion) criterion); + + case METADATA: + return matchCriterion((MetadataCriterion) criterion); + + case ETH_DST: + case ETH_SRC: + return matchCriterion((EthCriterion) criterion); + + case ETH_TYPE: + return matchCriterion((EthTypeCriterion) criterion); + + case VLAN_VID: + return matchCriterion((VlanIdCriterion) criterion); + + case VLAN_PCP: + return matchCriterion((VlanPcpCriterion) criterion); + + case IP_DSCP: + return matchCriterion((IPDscpCriterion) criterion); + + case IP_ECN: + return matchCriterion((IPEcnCriterion) criterion); + + case IP_PROTO: + return matchCriterion((IPProtocolCriterion) criterion); + + case IPV4_SRC: + case IPV4_DST: + case IPV6_SRC: + case IPV6_DST: + return matchCriterion((IPCriterion) criterion); + + case TCP_SRC: + case TCP_DST: + return matchCriterion((TcpPortCriterion) criterion); + + case UDP_SRC: + case UDP_DST: + return matchCriterion((UdpPortCriterion) criterion); + + case SCTP_SRC: + case SCTP_DST: + return matchCriterion((SctpPortCriterion) criterion); + + case ICMPV4_TYPE: + return matchCriterion((IcmpTypeCriterion) criterion); + + case ICMPV4_CODE: + return matchCriterion((IcmpCodeCriterion) criterion); + + case IPV6_FLABEL: + return matchCriterion((IPv6FlowLabelCriterion) criterion); + + case ICMPV6_TYPE: + return matchCriterion((Icmpv6TypeCriterion) criterion); + + case ICMPV6_CODE: + return matchCriterion((Icmpv6CodeCriterion) criterion); + + case IPV6_ND_TARGET: + return matchCriterion( + (IPv6NDTargetAddressCriterion) criterion); + + case IPV6_ND_SLL: + case IPV6_ND_TLL: + return matchCriterion( + (IPv6NDLinkLayerAddressCriterion) criterion); + + case MPLS_LABEL: + return matchCriterion((MplsCriterion) criterion); + + case IPV6_EXTHDR: + return matchCriterion( + (IPv6ExthdrFlagsCriterion) criterion); + + case OCH_SIGID: + return matchCriterion((OchSignalCriterion) criterion); + + case OCH_SIGTYPE: + return matchCriterion((OchSignalTypeCriterion) criterion); + + default: + // Don't know how to format this type + description.appendText("unknown criterion type " + + criterion.type()); + return false; + } + } + + @Override + public void describeTo(Description description) { + description.appendText(criterion.toString()); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DeviceCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DeviceCodecTest.java new file mode 100644 index 00000000..c7196e8b --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DeviceCodecTest.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.codec.impl; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.is; +import static org.onosproject.codec.impl.JsonCodecUtils.assertJsonEncodable; + +import org.junit.Test; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.DefaultDevice; +import org.onosproject.net.Device; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.device.DeviceServiceAdapter; + +/** + * Unit test for DeviceCodec. + */ +public class DeviceCodecTest { + + private Device device = new DefaultDevice(JsonCodecUtils.PID, + JsonCodecUtils.DID1, + Device.Type.SWITCH, + JsonCodecUtils.MFR, + JsonCodecUtils.HW, + JsonCodecUtils.SW1, + JsonCodecUtils.SN, + JsonCodecUtils.CID, + JsonCodecUtils.A1); + + + + @Test + public void deviceCodecTest() { + final MockCodecContext context = new MockCodecContext(); + context.registerService(DeviceService.class, new DeviceServiceAdapter()); + final JsonCodec codec = context.codec(Device.class); + assertThat(codec, is(notNullValue())); + final Device pojoIn = device; + + assertJsonEncodable(context, codec, pojoIn); + } + +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DriverCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DriverCodecTest.java new file mode 100644 index 00000000..a1c95176 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DriverCodecTest.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.codec.impl; + + +import java.util.Map; + +import org.junit.Test; +import org.onosproject.net.driver.Behaviour; +import org.onosproject.net.driver.DefaultDriver; +import org.onosproject.net.driver.Driver; +import org.onosproject.net.driver.TestBehaviour; +import org.onosproject.net.driver.TestBehaviourImpl; +import org.onosproject.net.driver.TestBehaviourTwo; +import org.onosproject.net.driver.TestBehaviourTwoImpl; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.ImmutableMap; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.onosproject.codec.impl.DriverJsonMatcher.matchesDriver; + +/** + * Unit tests for the driver codec. + */ +public class DriverCodecTest { + + @Test + public void codecTest() { + Map, Class> behaviours = + ImmutableMap.of(TestBehaviour.class, + TestBehaviourImpl.class, + TestBehaviourTwo.class, + TestBehaviourTwoImpl.class); + Map properties = + ImmutableMap.of("key1", "value1", "key2", "value2"); + + DefaultDriver parent = new DefaultDriver("parent", null, "Acme", + "HW1.2.3", "SW1.2.3", + behaviours, + properties); + DefaultDriver child = new DefaultDriver("child", parent, "Acme", + "HW1.2.3.1", "SW1.2.3.1", + behaviours, + properties); + + MockCodecContext context = new MockCodecContext(); + ObjectNode driverJson = context.codec(Driver.class).encode(child, context); + + assertThat(driverJson, matchesDriver(child)); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DriverJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DriverJsonMatcher.java new file mode 100644 index 00000000..6f0070e5 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/DriverJsonMatcher.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.codec.impl; + +import java.util.Map; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.net.driver.Driver; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Hamcrest matcher for drivers. + */ +public final class DriverJsonMatcher extends TypeSafeDiagnosingMatcher { + private final Driver driver; + + private DriverJsonMatcher(Driver driver) { + this.driver = driver; + } + + @Override + public boolean matchesSafely(JsonNode jsonDriver, Description description) { + // check id + String jsonDriverName = jsonDriver.get("name").asText(); + String driverName = driver.name(); + if (!jsonDriverName.equals(driverName)) { + description.appendText("name was " + jsonDriverName); + return false; + } + + + // check parent + String jsonParent = jsonDriver.get("parent").asText(); + String parent = driver.parent().name(); + if (!jsonParent.equals(parent)) { + description.appendText("parent was " + jsonParent); + return false; + } + + // check manufacturer + String jsonManufacturer = jsonDriver.get("manufacturer").asText(); + String manufacturer = driver.manufacturer(); + if (!jsonManufacturer.equals(manufacturer)) { + description.appendText("manufacturer was " + jsonManufacturer); + return false; + } + + // check HW version + String jsonHWVersion = jsonDriver.get("hwVersion").asText(); + String hwVersion = driver.hwVersion(); + if (!jsonHWVersion.equals(hwVersion)) { + description.appendText("HW version was " + jsonHWVersion); + return false; + } + + // check SW version + String jsonSWVersion = jsonDriver.get("swVersion").asText(); + String swVersion = driver.swVersion(); + if (!jsonSWVersion.equals(swVersion)) { + description.appendText("SW version was " + jsonSWVersion); + return false; + } + + // Check properties + JsonNode jsonProperties = jsonDriver.get("properties"); + if (driver.properties().size() != jsonProperties.size()) { + description.appendText("properties map size was was " + jsonProperties.size()); + return false; + } + for (Map.Entry entry : driver.properties().entrySet()) { + boolean propertyFound = false; + for (int propertyIndex = 0; propertyIndex < jsonProperties.size(); propertyIndex++) { + String jsonName = jsonProperties.get(propertyIndex).get("name").asText(); + String jsonValue = jsonProperties.get(propertyIndex).get("value").asText(); + if (!jsonName.equals(entry.getKey()) || + !jsonValue.equals(entry.getValue())) { + propertyFound = true; + break; + } + } + if (!propertyFound) { + description.appendText("property not found " + entry.getKey()); + return false; + } + } + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText(driver.toString()); + } + + /** + * Factory to allocate a driver matcher. + * + * @param driver driver object we are looking for + * @return matcher + */ + public static DriverJsonMatcher matchesDriver(Driver driver) { + return new DriverJsonMatcher(driver); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/EthernetCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/EthernetCodecTest.java new file mode 100644 index 00000000..847b0d09 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/EthernetCodecTest.java @@ -0,0 +1,55 @@ +/* + * 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.junit.Test; +import org.onlab.packet.Ethernet; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.codec.impl.EthernetJsonMatcher.matchesEthernet; + +/** + * Unit test for Ethernet class codec. + */ +public class EthernetCodecTest { + + /** + * Unit test for the ethernet object codec. + */ + @Test + public void ethernetCodecTest() { + final CodecContext context = new MockCodecContext(); + final JsonCodec ethernetCodec = context.codec(Ethernet.class); + assertThat(ethernetCodec, notNullValue()); + + final Ethernet eth1 = new Ethernet(); + eth1.setSourceMACAddress("11:22:33:44:55:01"); + eth1.setDestinationMACAddress("11:22:33:44:55:02"); + eth1.setPad(true); + eth1.setEtherType(Ethernet.TYPE_ARP); + eth1.setPriorityCode((byte) 7); + eth1.setVlanID((short) 33); + + final ObjectNode eth1Json = ethernetCodec.encode(eth1, context); + assertThat(eth1Json, notNullValue()); + assertThat(eth1Json, matchesEthernet(eth1)); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/EthernetJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/EthernetJsonMatcher.java new file mode 100644 index 00000000..c5827b91 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/EthernetJsonMatcher.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.codec.impl; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeMatcher; +import org.onlab.packet.Ethernet; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Hamcrest matcher for ethernet objects. + */ +public final class EthernetJsonMatcher extends TypeSafeMatcher { + + private final Ethernet ethernet; + private String reason = ""; + + private EthernetJsonMatcher(Ethernet ethernetValue) { + ethernet = ethernetValue; + } + + @Override + public boolean matchesSafely(JsonNode jsonEthernet) { + + // check source MAC + final JsonNode jsonSourceMacNode = jsonEthernet.get("srcMac"); + if (ethernet.getSourceMAC() != null) { + final String jsonSourceMac = jsonSourceMacNode.textValue(); + final String sourceMac = ethernet.getSourceMAC().toString(); + if (!jsonSourceMac.equals(sourceMac)) { + reason = "source MAC " + ethernet.getSourceMAC().toString(); + return false; + } + } else { + // source MAC not specified, JSON representation must be empty + if (jsonSourceMacNode != null) { + reason = "source mac should be null "; + return false; + } + } + + // check destination MAC + final JsonNode jsonDestinationMacNode = jsonEthernet.get("destMac"); + if (ethernet.getDestinationMAC() != null) { + final String jsonDestinationMac = jsonDestinationMacNode.textValue(); + final String destinationMac = ethernet.getDestinationMAC().toString(); + if (!jsonDestinationMac.equals(destinationMac)) { + reason = "destination MAC " + ethernet.getDestinationMAC().toString(); + return false; + } + } else { + // destination MAC not specified, JSON representation must be empty + if (jsonDestinationMacNode != null) { + reason = "destination mac should be null "; + return false; + } + } + + // check priority code + final short jsonPriorityCode = jsonEthernet.get("priorityCode").shortValue(); + final short priorityCode = ethernet.getPriorityCode(); + if (jsonPriorityCode != priorityCode) { + reason = "priority code " + Short.toString(ethernet.getPriorityCode()); + return false; + } + + // check vlanId + final short jsonVlanId = jsonEthernet.get("vlanId").shortValue(); + final short vlanId = ethernet.getVlanID(); + if (jsonVlanId != vlanId) { + reason = "vlan id " + Short.toString(ethernet.getVlanID()); + return false; + } + + // check etherType + final short jsonEtherType = jsonEthernet.get("etherType").shortValue(); + final short etherType = ethernet.getEtherType(); + if (jsonEtherType != etherType) { + reason = "etherType " + Short.toString(ethernet.getEtherType()); + return false; + } + + // check pad + final boolean jsonPad = jsonEthernet.get("pad").asBoolean(); + final boolean pad = ethernet.isPad(); + if (jsonPad != pad) { + reason = "pad " + Boolean.toString(ethernet.isPad()); + return false; + } + + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText(reason); + } + + /** + * Factory to allocate a ethernet matcher. + * + * @param ethernet ethernet object we are looking for + * @return matcher + */ + public static EthernetJsonMatcher matchesEthernet(Ethernet ethernet) { + return new EthernetJsonMatcher(ethernet); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java new file mode 100644 index 00000000..6c88ac1e --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/FlowRuleCodecTest.java @@ -0,0 +1,546 @@ +/* + * 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 java.io.IOException; +import java.io.InputStream; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.EthType; +import org.onlab.packet.Ethernet; +import org.onlab.packet.IpAddress; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.VlanId; +import org.onosproject.codec.JsonCodec; +import org.onosproject.core.CoreService; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.GridType; +import org.onosproject.net.Lambda; +import org.onosproject.net.OchSignal; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.EthCriterion; +import org.onosproject.net.flow.criteria.EthTypeCriterion; +import org.onosproject.net.flow.criteria.IPCriterion; +import org.onosproject.net.flow.criteria.IPDscpCriterion; +import org.onosproject.net.flow.criteria.IPEcnCriterion; +import org.onosproject.net.flow.criteria.IPProtocolCriterion; +import org.onosproject.net.flow.criteria.IPv6ExthdrFlagsCriterion; +import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion; +import org.onosproject.net.flow.criteria.IPv6NDLinkLayerAddressCriterion; +import org.onosproject.net.flow.criteria.IPv6NDTargetAddressCriterion; +import org.onosproject.net.flow.criteria.IcmpCodeCriterion; +import org.onosproject.net.flow.criteria.IcmpTypeCriterion; +import org.onosproject.net.flow.criteria.Icmpv6CodeCriterion; +import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion; +import org.onosproject.net.flow.criteria.IndexedLambdaCriterion; +import org.onosproject.net.flow.criteria.MplsCriterion; +import org.onosproject.net.flow.criteria.OchSignalCriterion; +import org.onosproject.net.flow.criteria.PortCriterion; +import org.onosproject.net.flow.criteria.SctpPortCriterion; +import org.onosproject.net.flow.criteria.TcpPortCriterion; +import org.onosproject.net.flow.criteria.TunnelIdCriterion; +import org.onosproject.net.flow.criteria.UdpPortCriterion; +import org.onosproject.net.flow.criteria.VlanIdCriterion; +import org.onosproject.net.flow.criteria.VlanPcpCriterion; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.net.flow.instructions.Instruction; +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.flow.instructions.L4ModificationInstruction; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.net.NetTestTools.APP_ID; + +/** + * Flow rule codec unit tests. + */ +public class FlowRuleCodecTest { + + MockCodecContext context; + JsonCodec flowRuleCodec; + final CoreService mockCoreService = createMock(CoreService.class); + + /** + * Sets up for each test. Creates a context and fetches the flow rule + * codec. + */ + @Before + public void setUp() { + context = new MockCodecContext(); + flowRuleCodec = context.codec(FlowRule.class); + assertThat(flowRuleCodec, notNullValue()); + + expect(mockCoreService.registerApplication(FlowRuleCodec.REST_APP_ID)) + .andReturn(APP_ID).anyTimes(); + replay(mockCoreService); + context.registerService(CoreService.class, mockCoreService); + } + + /** + * Reads in a rule from the given resource and decodes it. + * + * @param resourceName resource to use to read the JSON for the rule + * @return decoded flow rule + * @throws IOException if processing the resource fails + */ + private FlowRule getRule(String resourceName) throws IOException { + InputStream jsonStream = FlowRuleCodecTest.class + .getResourceAsStream(resourceName); + JsonNode json = context.mapper().readTree(jsonStream); + assertThat(json, notNullValue()); + FlowRule rule = flowRuleCodec.decode((ObjectNode) json, context); + assertThat(rule, notNullValue()); + return rule; + } + + /** + * Checks that the data shared by all the resources is correct for a + * given rule. + * + * @param rule rule to check + */ + private void checkCommonData(FlowRule rule) { + assertThat(rule.appId(), is(APP_ID.id())); + assertThat(rule.isPermanent(), is(false)); + assertThat(rule.timeout(), is(1)); + assertThat(rule.priority(), is(1)); + assertThat(rule.deviceId().toString(), is("of:0000000000000001")); + } + + /** + * Checks that a simple rule decodes properly. + * + * @throws IOException if the resource cannot be processed + */ + @Test + public void codecSimpleFlowTest() throws IOException { + FlowRule rule = getRule("simple-flow.json"); + + checkCommonData(rule); + + assertThat(rule.selector().criteria().size(), is(1)); + Criterion criterion1 = rule.selector().criteria().iterator().next(); + assertThat(criterion1.type(), is(Criterion.Type.ETH_TYPE)); + assertThat(((EthTypeCriterion) criterion1).ethType(), is(new EthType(2054))); + + assertThat(rule.treatment().allInstructions().size(), is(1)); + Instruction instruction1 = rule.treatment().allInstructions().get(0); + assertThat(instruction1.type(), is(Instruction.Type.OUTPUT)); + assertThat(((Instructions.OutputInstruction) instruction1).port(), is(PortNumber.CONTROLLER)); + } + + SortedMap instructions = new TreeMap<>(); + + /** + * Looks up an instruction in the instruction map based on type and subtype. + * + * @param type type string + * @param subType subtype string + * @return instruction that matches + */ + private Instruction getInstruction(Instruction.Type type, String subType) { + Instruction instruction = instructions.get(type.name() + "/" + subType); + assertThat(instruction, notNullValue()); + assertThat(instruction.type(), is(type)); + return instruction; + } + + /** + * Checks that a rule with one of each instruction type decodes properly. + * + * @throws IOException if the resource cannot be processed + */ + @Test + public void decodeInstructionsFlowTest() throws Exception { + FlowRule rule = getRule("instructions-flow.json"); + + checkCommonData(rule); + + rule.treatment().allInstructions() + .stream() + .forEach(instruction -> + { + String subType; + if (instruction.type() == Instruction.Type.L0MODIFICATION) { + subType = ((L0ModificationInstruction) instruction) + .subtype().name(); + } else if (instruction.type() == Instruction.Type.L2MODIFICATION) { + subType = ((L2ModificationInstruction) instruction) + .subtype().name(); + } else if (instruction.type() == Instruction.Type.L3MODIFICATION) { + subType = ((L3ModificationInstruction) instruction) + .subtype().name(); + } else if (instruction.type() == Instruction.Type.L4MODIFICATION) { + subType = ((L4ModificationInstruction) instruction) + .subtype().name(); + } else { + subType = ""; + } + instructions.put( + instruction.type().name() + "/" + subType, instruction); + }); + + assertThat(rule.treatment().allInstructions().size(), is(24)); + + Instruction instruction; + + instruction = getInstruction(Instruction.Type.OUTPUT, ""); + assertThat(instruction.type(), is(Instruction.Type.OUTPUT)); + assertThat(((Instructions.OutputInstruction) instruction).port(), is(PortNumber.CONTROLLER)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.ETH_SRC.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.ModEtherInstruction) instruction).mac(), + is(MacAddress.valueOf("12:34:56:78:90:12"))); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.ETH_DST.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.ModEtherInstruction) instruction).mac(), + is(MacAddress.valueOf("98:76:54:32:01:00"))); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.VLAN_ID.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.ModVlanIdInstruction) instruction).vlanId().toShort(), + is((short) 22)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.VLAN_PCP.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.ModVlanPcpInstruction) instruction).vlanPcp(), + is((byte) 1)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.MPLS_LABEL.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.ModMplsLabelInstruction) instruction) + .mplsLabel().toInt(), + is(MplsLabel.MAX_MPLS)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.MPLS_PUSH.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.PushHeaderInstructions) instruction) + .ethernetType().toShort(), + is(Ethernet.MPLS_UNICAST)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.MPLS_POP.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.PushHeaderInstructions) instruction) + .ethernetType().toShort(), + is(Ethernet.MPLS_UNICAST)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.DEC_MPLS_TTL.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(instruction, instanceOf(L2ModificationInstruction.ModMplsTtlInstruction.class)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.VLAN_POP.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(instruction, instanceOf(L2ModificationInstruction.PopVlanInstruction.class)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.VLAN_PUSH.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(instruction, instanceOf(L2ModificationInstruction.PushHeaderInstructions.class)); + + instruction = getInstruction(Instruction.Type.L2MODIFICATION, + L2ModificationInstruction.L2SubType.TUNNEL_ID.name()); + assertThat(instruction.type(), is(Instruction.Type.L2MODIFICATION)); + assertThat(((L2ModificationInstruction.ModTunnelIdInstruction) instruction) + .tunnelId(), is(100L)); + + instruction = getInstruction(Instruction.Type.L3MODIFICATION, + L3ModificationInstruction.L3SubType.IPV4_SRC.name()); + assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION)); + assertThat(((L3ModificationInstruction.ModIPInstruction) instruction).ip(), + is(IpAddress.valueOf("1.2.3.4"))); + + instruction = getInstruction(Instruction.Type.L3MODIFICATION, + L3ModificationInstruction.L3SubType.IPV4_DST.name()); + assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION)); + assertThat(((L3ModificationInstruction.ModIPInstruction) instruction).ip(), + is(IpAddress.valueOf("1.2.3.3"))); + + instruction = getInstruction(Instruction.Type.L3MODIFICATION, + L3ModificationInstruction.L3SubType.IPV6_SRC.name()); + assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION)); + assertThat(((L3ModificationInstruction.ModIPInstruction) instruction).ip(), + is(IpAddress.valueOf("1.2.3.2"))); + + instruction = getInstruction(Instruction.Type.L3MODIFICATION, + L3ModificationInstruction.L3SubType.IPV6_DST.name()); + assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION)); + assertThat(((L3ModificationInstruction.ModIPInstruction) instruction).ip(), + is(IpAddress.valueOf("1.2.3.1"))); + + instruction = getInstruction(Instruction.Type.L3MODIFICATION, + L3ModificationInstruction.L3SubType.IPV6_FLABEL.name()); + assertThat(instruction.type(), is(Instruction.Type.L3MODIFICATION)); + assertThat(((L3ModificationInstruction.ModIPv6FlowLabelInstruction) instruction) + .flowLabel(), + is(8)); + + instruction = getInstruction(Instruction.Type.L0MODIFICATION, + L0ModificationInstruction.L0SubType.LAMBDA.name()); + assertThat(instruction.type(), is(Instruction.Type.L0MODIFICATION)); + assertThat(((L0ModificationInstruction.ModLambdaInstruction) instruction) + .lambda(), + is((short) 7)); + + instruction = getInstruction(Instruction.Type.L0MODIFICATION, + L0ModificationInstruction.L0SubType.OCH.name()); + assertThat(instruction.type(), is(Instruction.Type.L0MODIFICATION)); + L0ModificationInstruction.ModOchSignalInstruction och = + (L0ModificationInstruction.ModOchSignalInstruction) instruction; + assertThat(och.lambda().spacingMultiplier(), is(4)); + assertThat(och.lambda().slotGranularity(), is(8)); + assertThat(och.lambda().gridType(), is(GridType.DWDM)); + assertThat(och.lambda().channelSpacing(), is(ChannelSpacing.CHL_100GHZ)); + + instruction = getInstruction(Instruction.Type.L4MODIFICATION, + L4ModificationInstruction.L4SubType.TCP_DST.name()); + assertThat(instruction.type(), is(Instruction.Type.L4MODIFICATION)); + assertThat(((L4ModificationInstruction.ModTransportPortInstruction) instruction) + .port().toInt(), is(40001)); + + instruction = getInstruction(Instruction.Type.L4MODIFICATION, + L4ModificationInstruction.L4SubType.TCP_SRC.name()); + assertThat(instruction.type(), is(Instruction.Type.L4MODIFICATION)); + assertThat(((L4ModificationInstruction.ModTransportPortInstruction) instruction) + .port().toInt(), is(40002)); + + instruction = getInstruction(Instruction.Type.L4MODIFICATION, + L4ModificationInstruction.L4SubType.UDP_DST.name()); + assertThat(instruction.type(), is(Instruction.Type.L4MODIFICATION)); + assertThat(((L4ModificationInstruction.ModTransportPortInstruction) instruction) + .port().toInt(), is(40003)); + + instruction = getInstruction(Instruction.Type.L4MODIFICATION, + L4ModificationInstruction.L4SubType.UDP_SRC.name()); + assertThat(instruction.type(), is(Instruction.Type.L4MODIFICATION)); + assertThat(((L4ModificationInstruction.ModTransportPortInstruction) instruction) + .port().toInt(), is(40004)); + } + + SortedMap criteria = new TreeMap<>(); + + /** + * Looks up a criterion in the instruction map based on type and subtype. + * + * @param type type string + * @return criterion that matches + */ + private Criterion getCriterion(Criterion.Type type) { + Criterion criterion = criteria.get(type.name()); + assertThat(criterion.type(), is(type)); + return criterion; + } + + /** + * Checks that a rule with one of each kind of criterion decodes properly. + * + * @throws IOException if the resource cannot be processed + */ + @Test + public void codecCriteriaFlowTest() throws Exception { + FlowRule rule = getRule("criteria-flow.json"); + + checkCommonData(rule); + + assertThat(rule.selector().criteria().size(), is(33)); + + rule.selector().criteria() + .stream() + .forEach(criterion -> + criteria.put(criterion.type().name(), criterion)); + + Criterion criterion; + + criterion = getCriterion(Criterion.Type.ETH_TYPE); + assertThat(((EthTypeCriterion) criterion).ethType(), is(new EthType(2054))); + + criterion = getCriterion(Criterion.Type.ETH_DST); + assertThat(((EthCriterion) criterion).mac(), + is(MacAddress.valueOf("00:11:22:33:44:55"))); + + criterion = getCriterion(Criterion.Type.ETH_SRC); + assertThat(((EthCriterion) criterion).mac(), + is(MacAddress.valueOf("00:11:22:33:44:55"))); + + criterion = getCriterion(Criterion.Type.IN_PORT); + assertThat(((PortCriterion) criterion).port(), + is(PortNumber.portNumber(23))); + + criterion = getCriterion(Criterion.Type.IN_PHY_PORT); + assertThat(((PortCriterion) criterion).port(), + is(PortNumber.portNumber(44))); + + criterion = getCriterion(Criterion.Type.VLAN_VID); + assertThat(((VlanIdCriterion) criterion).vlanId(), + is(VlanId.vlanId((short) 777))); + + criterion = getCriterion(Criterion.Type.VLAN_PCP); + assertThat(((VlanPcpCriterion) criterion).priority(), + is(((byte) 3))); + + criterion = getCriterion(Criterion.Type.IP_DSCP); + assertThat(((IPDscpCriterion) criterion).ipDscp(), + is(((byte) 2))); + + criterion = getCriterion(Criterion.Type.IP_ECN); + assertThat(((IPEcnCriterion) criterion).ipEcn(), + is(((byte) 1))); + + criterion = getCriterion(Criterion.Type.IP_PROTO); + assertThat(((IPProtocolCriterion) criterion).protocol(), + is(((short) 4))); + + criterion = getCriterion(Criterion.Type.IPV4_SRC); + assertThat(((IPCriterion) criterion).ip(), + is((IpPrefix.valueOf("1.2.0.0/32")))); + + criterion = getCriterion(Criterion.Type.IPV4_DST); + assertThat(((IPCriterion) criterion).ip(), + is((IpPrefix.valueOf("2.2.0.0/32")))); + + criterion = getCriterion(Criterion.Type.IPV6_SRC); + assertThat(((IPCriterion) criterion).ip(), + is((IpPrefix.valueOf("3.2.0.0/32")))); + + criterion = getCriterion(Criterion.Type.IPV6_DST); + assertThat(((IPCriterion) criterion).ip(), + is((IpPrefix.valueOf("4.2.0.0/32")))); + + criterion = getCriterion(Criterion.Type.TCP_SRC); + assertThat(((TcpPortCriterion) criterion).tcpPort().toInt(), + is(80)); + + criterion = getCriterion(Criterion.Type.TCP_DST); + assertThat(((TcpPortCriterion) criterion).tcpPort().toInt(), + is(443)); + + criterion = getCriterion(Criterion.Type.UDP_SRC); + assertThat(((UdpPortCriterion) criterion).udpPort().toInt(), + is(180)); + + criterion = getCriterion(Criterion.Type.UDP_DST); + assertThat(((UdpPortCriterion) criterion).udpPort().toInt(), + is(1443)); + + criterion = getCriterion(Criterion.Type.SCTP_SRC); + assertThat(((SctpPortCriterion) criterion).sctpPort().toInt(), + is(280)); + + criterion = getCriterion(Criterion.Type.SCTP_DST); + assertThat(((SctpPortCriterion) criterion).sctpPort().toInt(), + is(2443)); + + criterion = getCriterion(Criterion.Type.ICMPV4_TYPE); + assertThat(((IcmpTypeCriterion) criterion).icmpType(), + is((short) 24)); + + criterion = getCriterion(Criterion.Type.ICMPV4_CODE); + assertThat(((IcmpCodeCriterion) criterion).icmpCode(), + is((short) 16)); + + criterion = getCriterion(Criterion.Type.ICMPV6_TYPE); + assertThat(((Icmpv6TypeCriterion) criterion).icmpv6Type(), + is((short) 14)); + + criterion = getCriterion(Criterion.Type.ICMPV6_CODE); + assertThat(((Icmpv6CodeCriterion) criterion).icmpv6Code(), + is((short) 6)); + + criterion = getCriterion(Criterion.Type.IPV6_FLABEL); + assertThat(((IPv6FlowLabelCriterion) criterion).flowLabel(), + is(8)); + + criterion = getCriterion(Criterion.Type.IPV6_ND_TARGET); + assertThat(((IPv6NDTargetAddressCriterion) criterion) + .targetAddress().toString(), + is("1111:2222:3333:4444:5555:6666:7777:8888")); + + criterion = getCriterion(Criterion.Type.IPV6_ND_SLL); + assertThat(((IPv6NDLinkLayerAddressCriterion) criterion).mac(), + is(MacAddress.valueOf("00:11:22:33:44:56"))); + + criterion = getCriterion(Criterion.Type.IPV6_ND_TLL); + assertThat(((IPv6NDLinkLayerAddressCriterion) criterion).mac(), + is(MacAddress.valueOf("00:11:22:33:44:57"))); + + criterion = getCriterion(Criterion.Type.MPLS_LABEL); + assertThat(((MplsCriterion) criterion).label(), + is(MplsLabel.mplsLabel(123))); + + criterion = getCriterion(Criterion.Type.IPV6_EXTHDR); + assertThat(((IPv6ExthdrFlagsCriterion) criterion).exthdrFlags(), + is(99)); + + criterion = getCriterion(Criterion.Type.OCH_SIGID); + assertThat(((IndexedLambdaCriterion) criterion).lambda(), + is(Lambda.indexedLambda(122))); + + criterion = getCriterion(Criterion.Type.TUNNEL_ID); + assertThat(((TunnelIdCriterion) criterion).tunnelId(), + is(100L)); + } + + /** + * Checks that a rule with a SigId criterion decodes properly. + * + * @throws IOException if the resource cannot be processed + */ + @Test + public void codecSigIdCriteriaFlowTest() throws Exception { + FlowRule rule = getRule("sigid-flow.json"); + + checkCommonData(rule); + + assertThat(rule.selector().criteria().size(), is(1)); + Criterion criterion = rule.selector().criteria().iterator().next(); + assertThat(criterion.type(), is(Criterion.Type.OCH_SIGID)); + Lambda lambda = ((OchSignalCriterion) criterion).lambda(); + assertThat(lambda, instanceOf(OchSignal.class)); + OchSignal ochSignal = (OchSignal) lambda; + assertThat(ochSignal.spacingMultiplier(), is(3)); + assertThat(ochSignal.slotGranularity(), is(4)); + assertThat(ochSignal.gridType(), is(GridType.CWDM)); + assertThat(ochSignal.channelSpacing(), is(ChannelSpacing.CHL_25GHZ)); + } + +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupBucketJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupBucketJsonMatcher.java new file mode 100644 index 00000000..b3056216 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupBucketJsonMatcher.java @@ -0,0 +1,87 @@ +/* + * 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.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.net.group.GroupBucket; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Hamcrest matcher for instructions. + */ +public final class GroupBucketJsonMatcher extends TypeSafeDiagnosingMatcher { + + private final GroupBucket bucket; + + private GroupBucketJsonMatcher(GroupBucket bucket) { + this.bucket = bucket; + } + + /** + * Matches the contents of a group bucket. + * + * @param bucketJson JSON representation of bucket to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + @Override + public boolean matchesSafely(JsonNode bucketJson, Description description) { + + // check type + final String jsonType = bucketJson.get("type").textValue(); + if (!bucket.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final long jsonWeight = bucketJson.get("weight").longValue(); + if (bucket.weight() != jsonWeight) { + description.appendText("weight was " + jsonWeight); + return false; + } + + final long packetsJson = bucketJson.get("packets").asLong(); + if (bucket.packets() != packetsJson) { + description.appendText("packets was " + packetsJson); + return false; + } + + final long bytesJson = bucketJson.get("bytes").asLong(); + if (bucket.bytes() != bytesJson) { + description.appendText("bytes was " + packetsJson); + return false; + } + + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText(bucket.toString()); + } + + /** + * Factory to allocate an bucket matcher. + * + * @param bucket bucket object we are looking for + * @return matcher + */ + public static GroupBucketJsonMatcher matchesGroupBucket(GroupBucket bucket) { + return new GroupBucketJsonMatcher(bucket); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupCodecTest.java new file mode 100644 index 00000000..409f8eb3 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupCodecTest.java @@ -0,0 +1,61 @@ +/* + * 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.junit.Test; +import org.onosproject.core.DefaultGroupId; +import org.onosproject.net.NetTestTools; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.group.DefaultGroup; +import org.onosproject.net.group.DefaultGroupBucket; +import org.onosproject.net.group.GroupBucket; +import org.onosproject.net.group.GroupBuckets; +import org.onosproject.net.group.GroupDescription; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.ImmutableList; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.onosproject.codec.impl.GroupJsonMatcher.matchesGroup; + +/** + * Group codec unit tests. + */ + +public class GroupCodecTest { + + @Test + public void codecTest() { + GroupBucket bucket1 = DefaultGroupBucket + .createSelectGroupBucket(DefaultTrafficTreatment.emptyTreatment()); + GroupBucket bucket2 = DefaultGroupBucket + .createIndirectGroupBucket(DefaultTrafficTreatment.emptyTreatment()); + GroupBuckets buckets = new GroupBuckets(ImmutableList.of(bucket1, bucket2)); + + + DefaultGroup group = new DefaultGroup( + new DefaultGroupId(1), + NetTestTools.did("d1"), + GroupDescription.Type.INDIRECT, + buckets); + + MockCodecContext context = new MockCodecContext(); + GroupCodec codec = new GroupCodec(); + ObjectNode groupJson = codec.encode(group, context); + + assertThat(groupJson, matchesGroup(group)); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupJsonMatcher.java new file mode 100644 index 00000000..0e62c305 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/GroupJsonMatcher.java @@ -0,0 +1,120 @@ +/* + * 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.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.net.group.Group; +import org.onosproject.net.group.GroupBucket; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Hamcrest matcher for groups. + */ + +public final class GroupJsonMatcher extends TypeSafeDiagnosingMatcher { + + private final Group group; + + private GroupJsonMatcher(Group group) { + this.group = group; + } + + @Override + public boolean matchesSafely(JsonNode jsonGroup, Description description) { + // check id + String jsonGroupId = jsonGroup.get("id").asText(); + String groupId = group.id().toString(); + if (!jsonGroupId.equals(groupId)) { + description.appendText("group id was " + jsonGroupId); + return false; + } + + // check state + String jsonState = jsonGroup.get("state").asText(); + String state = group.state().toString(); + if (!jsonState.equals(state)) { + description.appendText("state was " + jsonState); + return false; + } + + // check life + long jsonLife = jsonGroup.get("life").asLong(); + long life = group.life(); + if (life != jsonLife) { + description.appendText("life was " + jsonLife); + return false; + } + + // check bytes + long jsonBytes = jsonGroup.get("bytes").asLong(); + long bytes = group.bytes(); + if (bytes != jsonBytes) { + description.appendText("bytes was " + jsonBytes); + return false; + } + + // check packets + long jsonPackets = jsonGroup.get("packets").asLong(); + long packets = group.packets(); + if (packets != jsonPackets) { + description.appendText("packets was " + jsonPackets); + return false; + } + + // check size of bucket array + JsonNode jsonBuckets = jsonGroup.get("buckets"); + if (jsonBuckets.size() != group.buckets().buckets().size()) { + description.appendText("buckets size was " + jsonBuckets.size()); + return false; + } + + // Check buckets + for (GroupBucket bucket : group.buckets().buckets()) { + boolean bucketFound = false; + for (int bucketIndex = 0; bucketIndex < jsonBuckets.size(); bucketIndex++) { + GroupBucketJsonMatcher bucketMatcher = + GroupBucketJsonMatcher.matchesGroupBucket(bucket); + if (bucketMatcher.matches(jsonBuckets.get(bucketIndex))) { + bucketFound = true; + break; + } + } + if (!bucketFound) { + description.appendText("bucket not found " + bucket.toString()); + return false; + } + } + + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText(group.toString()); + } + + /** + * Factory to allocate a group matcher. + * + * @param group group object we are looking for + * @return matcher + */ + public static GroupJsonMatcher matchesGroup(Group group) { + return new GroupJsonMatcher(group); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ImmutableCodecsTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ImmutableCodecsTest.java new file mode 100644 index 00000000..2081fa58 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/ImmutableCodecsTest.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.codec.impl; + +import org.junit.Test; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable; +import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutableBaseClass; + +/** + * Tests to assure that the codec classes follow the contract of having + * no local context. + */ +public class ImmutableCodecsTest { + + /** + * Checks that the codec classes adhere to the contract that there cannot + * be any local context in a codec. + */ + @Test + public void checkImmutability() { + assertThatClassIsImmutableBaseClass(AnnotatedCodec.class); + assertThatClassIsImmutable(AnnotationsCodec.class); + assertThatClassIsImmutable(ApplicationCodec.class); + assertThatClassIsImmutable(ConnectivityIntentCodec.class); + assertThatClassIsImmutable(ConnectPointCodec.class); + assertThatClassIsImmutable(ConstraintCodec.class); + assertThatClassIsImmutable(EncodeConstraintCodecHelper.class); + assertThatClassIsImmutable(DecodeConstraintCodecHelper.class); + assertThatClassIsImmutable(CriterionCodec.class); + assertThatClassIsImmutable(EncodeCriterionCodecHelper.class); + assertThatClassIsImmutable(DecodeCriterionCodecHelper.class); + assertThatClassIsImmutable(DeviceCodec.class); + assertThatClassIsImmutable(EthernetCodec.class); + assertThatClassIsImmutable(FlowEntryCodec.class); + assertThatClassIsImmutable(HostCodec.class); + assertThatClassIsImmutable(HostLocationCodec.class); + assertThatClassIsImmutable(HostToHostIntentCodec.class); + assertThatClassIsImmutable(InstructionCodec.class); + assertThatClassIsImmutable(EncodeInstructionCodecHelper.class); + assertThatClassIsImmutable(DecodeInstructionCodecHelper.class); + assertThatClassIsImmutable(IntentCodec.class); + assertThatClassIsImmutable(LinkCodec.class); + assertThatClassIsImmutable(PathCodec.class); + assertThatClassIsImmutable(PointToPointIntentCodec.class); + assertThatClassIsImmutable(PortCodec.class); + assertThatClassIsImmutable(TopologyClusterCodec.class); + assertThatClassIsImmutable(TopologyCodec.class); + assertThatClassIsImmutable(TrafficSelectorCodec.class); + assertThatClassIsImmutable(TrafficTreatmentCodec.class); + assertThatClassIsImmutable(FlowRuleCodec.class); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java new file mode 100644 index 00000000..bafbc0f1 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java @@ -0,0 +1,247 @@ +/* + * 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.junit.Before; +import org.junit.Test; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip6Address; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.packet.VlanId; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.GridType; +import org.onosproject.net.IndexedLambda; +import org.onosproject.net.Lambda; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.instructions.Instruction; +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 com.fasterxml.jackson.databind.node.ObjectNode; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.codec.impl.InstructionJsonMatcher.matchesInstruction; + +/** + * Unit tests for Instruction codec. + */ +public class InstructionCodecTest { + CodecContext context; + JsonCodec instructionCodec; + + /** + * Sets up for each test. Creates a context and fetches the instruction + * codec. + */ + @Before + public void setUp() { + context = new MockCodecContext(); + instructionCodec = context.codec(Instruction.class); + assertThat(instructionCodec, notNullValue()); + } + + /** + * Tests the encoding of push header instructions. + */ + @Test + public void pushHeaderInstructionsTest() { + final L2ModificationInstruction.PushHeaderInstructions instruction = + (L2ModificationInstruction.PushHeaderInstructions) Instructions.pushMpls(); + final ObjectNode instructionJson = instructionCodec.encode(instruction, context); + + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of drop instructions. + */ + @Test + public void dropInstructionTest() { + final Instructions.DropInstruction instruction = + Instructions.createDrop(); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of output instructions. + */ + @Test + public void outputInstructionTest() { + final Instructions.OutputInstruction instruction = + Instructions.createOutput(PortNumber.portNumber(22)); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod lambda instructions. + */ + @Test + public void modLambdaInstructionTest() { + final L0ModificationInstruction.ModLambdaInstruction instruction = + (L0ModificationInstruction.ModLambdaInstruction) + Instructions.modL0Lambda(new IndexedLambda(55)); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod OCh signal instructions. + */ + @Test + public void modOchSignalInstructionTest() { + L0ModificationInstruction.ModOchSignalInstruction instruction = + (L0ModificationInstruction.ModOchSignalInstruction) + Instructions.modL0Lambda(Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, 4, 8)); + ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod ether instructions. + */ + @Test + public void modEtherInstructionTest() { + final L2ModificationInstruction.ModEtherInstruction instruction = + (L2ModificationInstruction.ModEtherInstruction) + Instructions.modL2Src(MacAddress.valueOf("11:22:33:44:55:66")); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod vlan id instructions. + */ + @Test + public void modVlanIdInstructionTest() { + final L2ModificationInstruction.ModVlanIdInstruction instruction = + (L2ModificationInstruction.ModVlanIdInstruction) + Instructions.modVlanId(VlanId.vlanId((short) 12)); + + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod vlan pcp instructions. + */ + @Test + public void modVlanPcpInstructionTest() { + final L2ModificationInstruction.ModVlanPcpInstruction instruction = + (L2ModificationInstruction.ModVlanPcpInstruction) + Instructions.modVlanPcp((byte) 9); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod IPv4 src instructions. + */ + @Test + public void modIPSrcInstructionTest() { + final Ip4Address ip = Ip4Address.valueOf("1.2.3.4"); + final L3ModificationInstruction.ModIPInstruction instruction = + (L3ModificationInstruction.ModIPInstruction) + Instructions.modL3Src(ip); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod IPv4 dst instructions. + */ + @Test + public void modIPDstInstructionTest() { + final Ip4Address ip = Ip4Address.valueOf("1.2.3.4"); + final L3ModificationInstruction.ModIPInstruction instruction = + (L3ModificationInstruction.ModIPInstruction) + Instructions.modL3Dst(ip); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod IPv6 src instructions. + */ + @Test + public void modIPv6SrcInstructionTest() { + final Ip6Address ip = Ip6Address.valueOf("1111::2222"); + final L3ModificationInstruction.ModIPInstruction instruction = + (L3ModificationInstruction.ModIPInstruction) + Instructions.modL3IPv6Src(ip); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod IPv6 dst instructions. + */ + @Test + public void modIPv6DstInstructionTest() { + final Ip6Address ip = Ip6Address.valueOf("1111::2222"); + final L3ModificationInstruction.ModIPInstruction instruction = + (L3ModificationInstruction.ModIPInstruction) + Instructions.modL3IPv6Dst(ip); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod IPv6 flow label instructions. + */ + @Test + public void modIPv6FlowLabelInstructionTest() { + final int flowLabel = 0xfffff; + final L3ModificationInstruction.ModIPv6FlowLabelInstruction instruction = + (L3ModificationInstruction.ModIPv6FlowLabelInstruction) + Instructions.modL3IPv6FlowLabel(flowLabel); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + + /** + * Tests the encoding of mod MPLS label instructions. + */ + @Test + public void modMplsLabelInstructionTest() { + final L2ModificationInstruction.ModMplsLabelInstruction instruction = + (L2ModificationInstruction.ModMplsLabelInstruction) + Instructions.modMplsLabel(MplsLabel.mplsLabel(99)); + final ObjectNode instructionJson = + instructionCodec.encode(instruction, context); + assertThat(instructionJson, matchesInstruction(instruction)); + } + +} 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 new file mode 100644 index 00000000..72081e6c --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java @@ -0,0 +1,438 @@ +/* + * 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.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.net.flow.instructions.Instruction; + +import com.fasterxml.jackson.databind.JsonNode; + +import static org.onosproject.net.flow.instructions.Instructions.*; +import static org.onosproject.net.flow.instructions.L0ModificationInstruction.*; +import static org.onosproject.net.flow.instructions.L2ModificationInstruction.*; +import static org.onosproject.net.flow.instructions.L3ModificationInstruction.*; + +/** + * Hamcrest matcher for instructions. + */ +public final class InstructionJsonMatcher extends TypeSafeDiagnosingMatcher { + + private final Instruction instruction; + + private InstructionJsonMatcher(Instruction instructionValue) { + instruction = instructionValue; + } + + /** + * Matches the contents of a push header instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchPushHeaderInstruction(JsonNode instructionJson, + Description description) { + PushHeaderInstructions instructionToMatch = + (PushHeaderInstructions) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final JsonNode ethJson = instructionJson.get("ethernetType"); + if (ethJson == null) { + description.appendText("ethernetType was not null"); + return false; + } + + if (instructionToMatch.ethernetType().toShort() != ethJson.asInt()) { + description.appendText("ethernetType was " + ethJson); + return false; + } + + return true; + } + + /** + * Matches the contents of an output instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchOutputInstruction(JsonNode instructionJson, + Description description) { + OutputInstruction instructionToMatch = (OutputInstruction) instruction; + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final long jsonPort = instructionJson.get("port").asLong(); + if (instructionToMatch.port().toLong() != jsonPort) { + description.appendText("port was " + jsonPort); + return false; + } + + return true; + } + + /** + * Matches the contents of a mod lambda instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchModLambdaInstruction(JsonNode instructionJson, + Description description) { + ModLambdaInstruction instructionToMatch = + (ModLambdaInstruction) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final long jsonLambda = instructionJson.get("lambda").shortValue(); + if (instructionToMatch.lambda() != jsonLambda) { + description.appendText("lambda was " + jsonLambda); + return false; + } + + return true; + } + + /** + * Matches teh contents of a mod OCh singal instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents matches, false otherwise + */ + private boolean matchModOchSingalInstruction(JsonNode instructionJson, + Description description) { + ModOchSignalInstruction instructionToMatch = + (ModOchSignalInstruction) instruction; + + String jsonSubType = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubType)) { + description.appendText("subtype was " + jsonSubType); + return false; + } + + String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + String jsonGridType = instructionJson.get("gridType").textValue(); + if (!instructionToMatch.lambda().gridType().name().equals(jsonGridType)) { + description.appendText("gridType was " + jsonGridType); + return false; + } + + String jsonChannelSpacing = instructionJson.get("channelSpacing").textValue(); + if (!instructionToMatch.lambda().channelSpacing().name().equals(jsonChannelSpacing)) { + description.appendText("channelSpacing was " + jsonChannelSpacing); + return false; + } + + int jsonSpacingMultiplier = instructionJson.get("spacingMultiplier").intValue(); + if (instructionToMatch.lambda().spacingMultiplier() != jsonSpacingMultiplier) { + description.appendText("spacingMultiplier was " + jsonSpacingMultiplier); + return false; + } + + int jsonSlotGranularity = instructionJson.get("slotGranularity").intValue(); + if (instructionToMatch.lambda().slotGranularity() != jsonSlotGranularity) { + description.appendText("slotGranularity was " + jsonSlotGranularity); + return false; + } + + return true; + } + + /** + * Matches the contents of a mod Ethernet instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchModEtherInstruction(JsonNode instructionJson, + Description description) { + ModEtherInstruction instructionToMatch = + (ModEtherInstruction) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final String jsonMac = instructionJson.get("mac").textValue(); + final String mac = instructionToMatch.mac().toString(); + if (!mac.equals(jsonMac)) { + description.appendText("mac was " + jsonMac); + return false; + } + + return true; + } + + /** + * Matches the contents of a mod vlan id instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchModVlanIdInstruction(JsonNode instructionJson, + Description description) { + ModVlanIdInstruction instructionToMatch = + (ModVlanIdInstruction) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final short jsonVlanId = instructionJson.get("vlanId").shortValue(); + final short vlanId = instructionToMatch.vlanId().toShort(); + if (jsonVlanId != vlanId) { + description.appendText("vlan id was " + jsonVlanId); + return false; + } + + return true; + } + + /** + * Matches the contents of a mod vlan pcp instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchModVlanPcpInstruction(JsonNode instructionJson, + Description description) { + ModVlanPcpInstruction instructionToMatch = + (ModVlanPcpInstruction) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final short jsonVlanPcp = instructionJson.get("vlanPcp").shortValue(); + final short vlanId = instructionToMatch.vlanPcp(); + if (jsonVlanPcp != vlanId) { + description.appendText("vlan pcp was " + jsonVlanPcp); + return false; + } + + return true; + } + + /** + * Matches the contents of a mod ip instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchModIpInstruction(JsonNode instructionJson, + Description description) { + ModIPInstruction instructionToMatch = + (ModIPInstruction) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final String jsonIp = instructionJson.get("ip").textValue(); + final String ip = instructionToMatch.ip().toString(); + if (!ip.equals(jsonIp)) { + description.appendText("ip was " + jsonIp); + return false; + } + + return true; + } + + /** + * Matches the contents of a mod IPv6 Flow Label instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchModIPv6FlowLabelInstruction(JsonNode instructionJson, + Description description) { + ModIPv6FlowLabelInstruction instructionToMatch = + (ModIPv6FlowLabelInstruction) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final int jsonFlowLabel = instructionJson.get("flowLabel").intValue(); + final int flowLabel = instructionToMatch.flowLabel(); + if (flowLabel != jsonFlowLabel) { + description.appendText("IPv6 flow label was " + jsonFlowLabel); + return false; + } + + return true; + } + + /** + * Matches the contents of a mod MPLS label instruction. + * + * @param instructionJson JSON instruction to match + * @param description Description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchModMplsLabelInstruction(JsonNode instructionJson, + Description description) { + ModMplsLabelInstruction instructionToMatch = + (ModMplsLabelInstruction) instruction; + final String jsonSubtype = instructionJson.get("subtype").textValue(); + if (!instructionToMatch.subtype().name().equals(jsonSubtype)) { + description.appendText("subtype was " + jsonSubtype); + return false; + } + + final String jsonType = instructionJson.get("type").textValue(); + if (!instructionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + + final int jsonLabel = instructionJson.get("label").intValue(); + final int label = instructionToMatch.mplsLabel().toInt(); + if (label != jsonLabel) { + description.appendText("MPLS label was " + jsonLabel); + return false; + } + + return true; + } + + @Override + public boolean matchesSafely(JsonNode jsonInstruction, Description description) { + + // check type + final JsonNode jsonTypeNode = jsonInstruction.get("type"); + final String jsonType = jsonTypeNode.textValue(); + final String type = instruction.type().name(); + if (!jsonType.equals(type)) { + description.appendText("type was " + type); + return false; + } + + if (instruction instanceof PushHeaderInstructions) { + return matchPushHeaderInstruction(jsonInstruction, description); + } else if (instruction instanceof DropInstruction) { + return true; + } else if (instruction instanceof OutputInstruction) { + return matchOutputInstruction(jsonInstruction, description); + } else if (instruction instanceof ModLambdaInstruction) { + return matchModLambdaInstruction(jsonInstruction, description); + } else if (instruction instanceof ModOchSignalInstruction) { + return matchModOchSingalInstruction(jsonInstruction, description); + } else if (instruction instanceof ModEtherInstruction) { + return matchModEtherInstruction(jsonInstruction, description); + } else if (instruction instanceof ModVlanIdInstruction) { + return matchModVlanIdInstruction(jsonInstruction, description); + } else if (instruction instanceof ModVlanPcpInstruction) { + return matchModVlanPcpInstruction(jsonInstruction, description); + } else if (instruction instanceof ModIPInstruction) { + return matchModIpInstruction(jsonInstruction, description); + } else if (instruction instanceof ModIPv6FlowLabelInstruction) { + return matchModIPv6FlowLabelInstruction(jsonInstruction, + description); + } else if (instruction instanceof ModMplsLabelInstruction) { + return matchModMplsLabelInstruction(jsonInstruction, description); + } + + return false; + } + + @Override + public void describeTo(Description description) { + description.appendText(instruction.toString()); + } + + /** + * Factory to allocate an instruction matcher. + * + * @param instruction instruction object we are looking for + * @return matcher + */ + public static InstructionJsonMatcher matchesInstruction(Instruction instruction) { + return new InstructionJsonMatcher(instruction); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentCodecTest.java new file mode 100644 index 00000000..7cbce4d1 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentCodecTest.java @@ -0,0 +1,288 @@ +/* + * 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 java.io.IOException; +import java.io.InputStream; +import java.time.Duration; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.IpPrefix; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onlab.util.Bandwidth; +import org.onosproject.codec.JsonCodec; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.core.DefaultApplicationId; +import org.onosproject.net.ChannelSpacing; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.GridType; +import org.onosproject.net.HostId; +import org.onosproject.net.IndexedLambda; +import org.onosproject.net.Lambda; +import org.onosproject.net.NetTestTools; +import org.onosproject.net.OchSignalType; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.criteria.Criteria; +import org.onosproject.net.flow.instructions.Instructions; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.EthCriterion; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.intent.AbstractIntentTest; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.HostToHostIntent; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.IntentServiceAdapter; +import org.onosproject.net.intent.PointToPointIntent; +import org.onosproject.net.intent.constraint.AnnotationConstraint; +import org.onosproject.net.intent.constraint.AsymmetricPathConstraint; +import org.onosproject.net.intent.constraint.BandwidthConstraint; +import org.onosproject.net.intent.constraint.LambdaConstraint; +import org.onosproject.net.intent.constraint.LatencyConstraint; +import org.onosproject.net.intent.constraint.ObstacleConstraint; +import org.onosproject.net.intent.constraint.WaypointConstraint; +import org.onosproject.net.resource.link.BandwidthResource; +import org.onosproject.net.resource.link.LambdaResource; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.ImmutableList; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.codec.impl.IntentJsonMatcher.matchesIntent; +import static org.onosproject.net.NetTestTools.did; +import static org.onosproject.net.NetTestTools.hid; +import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction; + +/** + * Unit tests for the host to host intent class codec. + */ +public class IntentCodecTest extends AbstractIntentTest { + + private final HostId id1 = hid("12:34:56:78:91:ab/1"); + private final HostId id2 = hid("12:34:56:78:92:ab/1"); + private final ApplicationId appId = new DefaultApplicationId(3, "test"); + final TrafficSelector emptySelector = + DefaultTrafficSelector.emptySelector(); + final TrafficTreatment emptyTreatment = + DefaultTrafficTreatment.emptyTreatment(); + private final MockCodecContext context = new MockCodecContext(); + final CoreService mockCoreService = createMock(CoreService.class); + + @Before + public void setUpIntentService() { + final IntentService mockIntentService = new IntentServiceAdapter(); + context.registerService(IntentService.class, mockIntentService); + context.registerService(CoreService.class, mockCoreService); + expect(mockCoreService.getAppId(appId.name())) + .andReturn(appId); + replay(mockCoreService); + } + + /** + * Tests the encoding of a host to host intent. + */ + @Test + public void hostToHostIntent() { + final HostToHostIntent intent = + HostToHostIntent.builder() + .appId(appId) + .one(id1) + .two(id2) + .build(); + + final JsonCodec intentCodec = + context.codec(HostToHostIntent.class); + assertThat(intentCodec, notNullValue()); + + final ObjectNode intentJson = intentCodec.encode(intent, context); + assertThat(intentJson, matchesIntent(intent)); + } + + /** + * Tests the encoding of a point to point intent. + */ + @Test + public void pointToPointIntent() { + ConnectPoint ingress = NetTestTools.connectPoint("ingress", 1); + ConnectPoint egress = NetTestTools.connectPoint("egress", 2); + + final PointToPointIntent intent = + PointToPointIntent.builder() + .appId(appId) + .selector(emptySelector) + .treatment(emptyTreatment) + .ingressPoint(ingress) + .egressPoint(egress).build(); + + final JsonCodec intentCodec = + context.codec(PointToPointIntent.class); + assertThat(intentCodec, notNullValue()); + + final ObjectNode intentJson = intentCodec.encode(intent, context); + assertThat(intentJson, matchesIntent(intent)); + } + + /** + * Tests the encoding of an intent with treatment, selector and constraints + * specified. + */ + @Test + public void intentWithTreatmentSelectorAndConstraints() { + ConnectPoint ingress = NetTestTools.connectPoint("ingress", 1); + ConnectPoint egress = NetTestTools.connectPoint("egress", 2); + DeviceId did1 = did("device1"); + DeviceId did2 = did("device2"); + DeviceId did3 = did("device3"); + Lambda ochSignal = Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, 4, 8); + final TrafficSelector selector = DefaultTrafficSelector.builder() + .matchIPProtocol((byte) 3) + .matchMplsLabel(MplsLabel.mplsLabel(4)) + .add(Criteria.matchOchSignalType(OchSignalType.FIXED_GRID)) + .add(Criteria.matchLambda(ochSignal)) + .matchEthDst(MacAddress.BROADCAST) + .matchIPDst(IpPrefix.valueOf("1.2.3.4/24")) + .build(); + final TrafficTreatment treatment = DefaultTrafficTreatment.builder() + .add(Instructions.modL0Lambda(new IndexedLambda(33))) + .setMpls(MplsLabel.mplsLabel(44)) + .setOutput(PortNumber.CONTROLLER) + .setEthDst(MacAddress.BROADCAST) + .build(); + + final List constraints = + ImmutableList.of( + new BandwidthConstraint(new BandwidthResource(Bandwidth.bps(1.0))), + new LambdaConstraint(LambdaResource.valueOf(3)), + new AnnotationConstraint("key", 33.0), + new AsymmetricPathConstraint(), + new LatencyConstraint(Duration.ofSeconds(2)), + new ObstacleConstraint(did1, did2), + new WaypointConstraint(did3)); + + final PointToPointIntent intent = + PointToPointIntent.builder() + .appId(appId) + .selector(selector) + .treatment(treatment) + .ingressPoint(ingress) + .egressPoint(egress) + .constraints(constraints) + .build(); + + + final JsonCodec intentCodec = + context.codec(PointToPointIntent.class); + assertThat(intentCodec, notNullValue()); + + final ObjectNode intentJson = intentCodec.encode(intent, context); + assertThat(intentJson, matchesIntent(intent)); + + } + + /** + * Reads in a rule from the given resource and decodes it. + * + * @param resourceName resource to use to read the JSON for the rule + * @return decoded flow rule + * @throws IOException if processing the resource fails + */ + private Intent getIntent(String resourceName, JsonCodec intentCodec) throws IOException { + InputStream jsonStream = FlowRuleCodecTest.class + .getResourceAsStream(resourceName); + JsonNode json = context.mapper().readTree(jsonStream); + assertThat(json, notNullValue()); + Intent intent = (Intent) intentCodec.decode((ObjectNode) json, context); + assertThat(intent, notNullValue()); + return intent; + } + + /** + * Tests the point to point intent JSON codec. + * + * @throws IOException if JSON processing fails + */ + @Test + public void decodePointToPointIntent() throws IOException { + JsonCodec intentCodec = context.codec(Intent.class); + assertThat(intentCodec, notNullValue()); + + Intent intent = getIntent("PointToPointIntent.json", intentCodec); + assertThat(intent, notNullValue()); + assertThat(intent, instanceOf(PointToPointIntent.class)); + + PointToPointIntent pointIntent = (PointToPointIntent) intent; + assertThat(pointIntent.priority(), is(55)); + assertThat(pointIntent.ingressPoint().deviceId(), is(did("0000000000000001"))); + assertThat(pointIntent.ingressPoint().port(), is(PortNumber.portNumber(1))); + assertThat(pointIntent.egressPoint().deviceId(), is(did("0000000000000007"))); + assertThat(pointIntent.egressPoint().port(), is(PortNumber.portNumber(2))); + + assertThat(pointIntent.constraints(), hasSize(1)); + + assertThat(pointIntent.selector(), notNullValue()); + assertThat(pointIntent.selector().criteria(), hasSize(1)); + Criterion criterion1 = pointIntent.selector().criteria().iterator().next(); + assertThat(criterion1, instanceOf(EthCriterion.class)); + EthCriterion ethCriterion = (EthCriterion) criterion1; + assertThat(ethCriterion.mac().toString(), is("11:22:33:44:55:66")); + assertThat(ethCriterion.type().name(), is("ETH_DST")); + + assertThat(pointIntent.treatment(), notNullValue()); + assertThat(pointIntent.treatment().allInstructions(), hasSize(1)); + Instruction instruction1 = pointIntent.treatment().allInstructions().iterator().next(); + assertThat(instruction1, instanceOf(ModEtherInstruction.class)); + ModEtherInstruction ethInstruction = (ModEtherInstruction) instruction1; + assertThat(ethInstruction.mac().toString(), is("22:33:44:55:66:77")); + assertThat(ethInstruction.type().toString(), is("L2MODIFICATION")); + assertThat(ethInstruction.subtype().toString(), is("ETH_SRC")); + } + + /** + * Tests the host to host intent JSON codec. + * + * @throws IOException + */ + @Test + public void decodeHostToHostIntent() throws IOException { + JsonCodec intentCodec = context.codec(Intent.class); + assertThat(intentCodec, notNullValue()); + + Intent intent = getIntent("HostToHostIntent.json", intentCodec); + assertThat(intent, notNullValue()); + assertThat(intent, instanceOf(HostToHostIntent.class)); + + HostToHostIntent hostIntent = (HostToHostIntent) intent; + assertThat(hostIntent.priority(), is(7)); + assertThat(hostIntent.constraints(), hasSize(1)); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java new file mode 100644 index 00000000..e485a5fa --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/IntentJsonMatcher.java @@ -0,0 +1,512 @@ +/* + * 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 java.util.List; +import java.util.Set; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.NetworkResource; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.intent.ConnectivityIntent; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.HostToHostIntent; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.PointToPointIntent; +import org.onosproject.net.intent.constraint.AnnotationConstraint; +import org.onosproject.net.intent.constraint.BandwidthConstraint; +import org.onosproject.net.intent.constraint.LambdaConstraint; +import org.onosproject.net.intent.constraint.LatencyConstraint; +import org.onosproject.net.intent.constraint.LinkTypeConstraint; +import org.onosproject.net.intent.constraint.ObstacleConstraint; +import org.onosproject.net.intent.constraint.WaypointConstraint; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Hamcrest matcher to check that an intent representation in JSON matches + * the actual intent. + */ +public final class IntentJsonMatcher extends TypeSafeDiagnosingMatcher { + + private final Intent intent; + + /** + * Constructor is private, use factory method. + * + * @param intentValue the intent object to compare against + */ + private IntentJsonMatcher(Intent intentValue) { + intent = intentValue; + } + + /** + * Matches the JSON representation of a host to host intent. + * + * @param jsonIntent JSON representation of the intent + * @param description Description object used for recording errors + * @return true if the JSON matches the intent, false otherwise + */ + private boolean matchHostToHostIntent(JsonNode jsonIntent, Description description) { + final HostToHostIntent hostToHostIntent = (HostToHostIntent) intent; + + // check host one + final String host1 = hostToHostIntent.one().toString(); + final String jsonHost1 = jsonIntent.get("one").asText(); + if (!host1.equals(jsonHost1)) { + description.appendText("host one was " + jsonHost1); + return false; + } + + // check host 2 + final String host2 = hostToHostIntent.two().toString(); + final String jsonHost2 = jsonIntent.get("two").asText(); + if (!host2.equals(jsonHost2)) { + description.appendText("host two was " + jsonHost2); + return false; + } + return true; + } + + /** + * Matches the JSON representation of a point to point intent. + * + * @param jsonIntent JSON representation of the intent + * @param description Description object used for recording errors + * @return true if the JSON matches the intent, false otherwise + */ + private boolean matchPointToPointIntent(JsonNode jsonIntent, Description description) { + final PointToPointIntent pointToPointIntent = (PointToPointIntent) intent; + + // check ingress connection + final ConnectPoint ingress = pointToPointIntent.ingressPoint(); + final ConnectPointJsonMatcher ingressMatcher = + ConnectPointJsonMatcher.matchesConnectPoint(ingress); + final JsonNode jsonIngress = jsonIntent.get("ingressPoint"); + final boolean ingressMatches = + ingressMatcher.matchesSafely(jsonIngress, description); + + if (!ingressMatches) { + description.appendText("ingress was " + jsonIngress); + return false; + } + + // check egress connection + final ConnectPoint egress = pointToPointIntent.egressPoint(); + final ConnectPointJsonMatcher egressMatcher = + ConnectPointJsonMatcher.matchesConnectPoint(egress); + final JsonNode jsonEgress = jsonIntent.get("egressPoint"); + final boolean egressMatches = + egressMatcher.matchesSafely(jsonEgress, description); + + if (!egressMatches) { + description.appendText("egress was " + jsonEgress); + return false; + } + + return true; + } + + + /** + * Matches a bandwidth constraint against a JSON representation of the + * constraint. + * + * @param bandwidthConstraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchBandwidthConstraint(BandwidthConstraint bandwidthConstraint, + JsonNode constraintJson) { + final JsonNode bandwidthJson = constraintJson.get("bandwidth"); + return bandwidthJson != null + && constraintJson.get("bandwidth").asDouble() + == bandwidthConstraint.bandwidth().toDouble(); + } + + /** + * Matches a lamdba constraint against a JSON representation of the + * constraint. + * + * @param lambdaConstraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchLambdaConstraint(LambdaConstraint lambdaConstraint, + JsonNode constraintJson) { + final JsonNode lambdaJson = constraintJson.get("lambda"); + return lambdaJson != null + && constraintJson.get("lambda").asInt() + == lambdaConstraint.lambda().toInt(); + } + + /** + * Matches a link type constraint against a JSON representation of the + * constraint. + * + * @param linkTypeConstraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchLinkTypeConstraint(LinkTypeConstraint linkTypeConstraint, + JsonNode constraintJson) { + final JsonNode inclusiveJson = constraintJson.get("inclusive"); + final JsonNode typesJson = constraintJson.get("types"); + + if (typesJson.size() != linkTypeConstraint.types().size()) { + return false; + } + + int foundType = 0; + for (Link.Type type : linkTypeConstraint.types()) { + for (int jsonIndex = 0; jsonIndex < typesJson.size(); jsonIndex++) { + if (type.name().equals(typesJson.get(jsonIndex).asText())) { + foundType++; + break; + } + } + } + return (inclusiveJson != null && + inclusiveJson.asBoolean() == linkTypeConstraint.isInclusive()) && + foundType == typesJson.size(); + } + + /** + * Matches an annotation constraint against a JSON representation of the + * constraint. + * + * @param annotationConstraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchAnnotationConstraint(AnnotationConstraint annotationConstraint, + JsonNode constraintJson) { + final JsonNode keyJson = constraintJson.get("key"); + final JsonNode thresholdJson = constraintJson.get("threshold"); + return (keyJson != null + && keyJson.asText().equals(annotationConstraint.key())) && + (thresholdJson != null + && thresholdJson.asDouble() == annotationConstraint.threshold()); + } + + /** + * Matches a latency constraint against a JSON representation of the + * constraint. + * + * @param latencyConstraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchLatencyConstraint(LatencyConstraint latencyConstraint, + JsonNode constraintJson) { + final JsonNode latencyJson = constraintJson.get("latencyMillis"); + return (latencyJson != null + && latencyJson.asInt() == latencyConstraint.latency().toMillis()); + } + + /** + * Matches an obstacle constraint against a JSON representation of the + * constraint. + * + * @param obstacleConstraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchObstacleConstraint(ObstacleConstraint obstacleConstraint, + JsonNode constraintJson) { + final JsonNode obstaclesJson = constraintJson.get("obstacles"); + + if (obstaclesJson.size() != obstacleConstraint.obstacles().size()) { + return false; + } + + for (int obstaclesIndex = 0; obstaclesIndex < obstaclesJson.size(); + obstaclesIndex++) { + boolean obstacleFound = false; + final String obstacleJson = obstaclesJson.get(obstaclesIndex) + .asText(); + for (DeviceId obstacle : obstacleConstraint.obstacles()) { + if (obstacle.toString().equals(obstacleJson)) { + obstacleFound = true; + } + } + if (!obstacleFound) { + return false; + } + } + return true; + } + + /** + * Matches a waypoint constraint against a JSON representation of the + * constraint. + * + * @param waypointConstraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchWaypointConstraint(WaypointConstraint waypointConstraint, + JsonNode constraintJson) { + final JsonNode waypointsJson = constraintJson.get("waypoints"); + + if (waypointsJson.size() != waypointConstraint.waypoints().size()) { + return false; + } + + for (int waypointsIndex = 0; waypointsIndex < waypointsJson.size(); + waypointsIndex++) { + boolean waypointFound = false; + final String waypointJson = waypointsJson.get(waypointsIndex) + .asText(); + for (DeviceId waypoint : waypointConstraint.waypoints()) { + if (waypoint.toString().equals(waypointJson)) { + waypointFound = true; + } + } + if (!waypointFound) { + return false; + } + } + return true; + } + + + /** + * Matches a constraint against a JSON representation of the + * constraint. + * + * @param constraint constraint object to match + * @param constraintJson JSON representation of the constraint + * @return true if the constraint and JSON match, false otherwise. + */ + private boolean matchConstraint(Constraint constraint, JsonNode constraintJson) { + final JsonNode typeJson = constraintJson.get("type"); + if (!typeJson.asText().equals(constraint.getClass().getSimpleName())) { + return false; + } + if (constraint instanceof BandwidthConstraint) { + return matchBandwidthConstraint((BandwidthConstraint) constraint, + constraintJson); + } else if (constraint instanceof LambdaConstraint) { + return matchLambdaConstraint((LambdaConstraint) constraint, + constraintJson); + } else if (constraint instanceof LinkTypeConstraint) { + return matchLinkTypeConstraint((LinkTypeConstraint) constraint, + constraintJson); + } else if (constraint instanceof AnnotationConstraint) { + return matchAnnotationConstraint((AnnotationConstraint) constraint, + constraintJson); + } else if (constraint instanceof LatencyConstraint) { + return matchLatencyConstraint((LatencyConstraint) constraint, + constraintJson); + } else if (constraint instanceof ObstacleConstraint) { + return matchObstacleConstraint((ObstacleConstraint) constraint, + constraintJson); + } else if (constraint instanceof WaypointConstraint) { + return matchWaypointConstraint((WaypointConstraint) constraint, + constraintJson); + } + return true; + } + + /** + * Matches the JSON representation of a connectivity intent. Calls the + * matcher for the connectivity intent subtype. + * + * @param jsonIntent JSON representation of the intent + * @param description Description object used for recording errors + * @return true if the JSON matches the intent, false otherwise + */ + private boolean matchConnectivityIntent(JsonNode jsonIntent, Description description) { + final ConnectivityIntent connectivityIntent = (ConnectivityIntent) intent; + + // check selector + final JsonNode jsonSelector = jsonIntent.get("selector"); + final TrafficSelector selector = connectivityIntent.selector(); + final Set criteria = selector.criteria(); + final JsonNode jsonCriteria = jsonSelector.get("criteria"); + if (jsonCriteria.size() != criteria.size()) { + description.appendText("size of criteria array is " + + Integer.toString(jsonCriteria.size())); + return false; + } + + for (Criterion criterion : criteria) { + boolean criterionFound = false; + for (int criterionIndex = 0; criterionIndex < jsonCriteria.size(); criterionIndex++) { + final CriterionJsonMatcher criterionMatcher = + CriterionJsonMatcher.matchesCriterion(criterion); + if (criterionMatcher.matches(jsonCriteria.get(criterionIndex))) { + criterionFound = true; + break; + } + } + if (!criterionFound) { + description.appendText("criterion not found " + criterion.toString()); + return false; + } + } + + // check treatment + final JsonNode jsonTreatment = jsonIntent.get("treatment"); + final TrafficTreatment treatment = connectivityIntent.treatment(); + final List instructions = treatment.immediate(); + final JsonNode jsonInstructions = jsonTreatment.get("instructions"); + if (jsonInstructions.size() != instructions.size()) { + description.appendText("size of instructions array is " + + Integer.toString(jsonInstructions.size())); + return false; + } + + for (Instruction instruction : instructions) { + boolean instructionFound = false; + for (int instructionIndex = 0; instructionIndex < jsonInstructions.size(); instructionIndex++) { + final InstructionJsonMatcher instructionMatcher = + InstructionJsonMatcher.matchesInstruction(instruction); + if (instructionMatcher.matches(jsonInstructions.get(instructionIndex))) { + instructionFound = true; + break; + } + } + if (!instructionFound) { + description.appendText("instruction not found " + instruction.toString()); + return false; + } + } + + // Check constraints + final JsonNode jsonConstraints = jsonIntent.get("constraints"); + if (connectivityIntent.constraints() != null) { + if (connectivityIntent.constraints().size() != jsonConstraints.size()) { + description.appendText("constraints array size was " + + Integer.toString(jsonConstraints.size())); + return false; + } + for (final Constraint constraint : connectivityIntent.constraints()) { + boolean constraintFound = false; + for (int constraintIndex = 0; constraintIndex < jsonConstraints.size(); + constraintIndex++) { + final JsonNode value = jsonConstraints.get(constraintIndex); + if (matchConstraint(constraint, value)) { + constraintFound = true; + } + } + if (!constraintFound) { + final String constraintString = constraint.toString(); + description.appendText("constraint missing " + constraintString); + return false; + } + } + } else if (jsonConstraints.size() != 0) { + description.appendText("constraint array not empty"); + return false; + } + + if (connectivityIntent instanceof HostToHostIntent) { + return matchHostToHostIntent(jsonIntent, description); + } else if (connectivityIntent instanceof PointToPointIntent) { + return matchPointToPointIntent(jsonIntent, description); + } else { + description.appendText("class of connectivity intent is unknown"); + return false; + } + } + + @Override + public boolean matchesSafely(JsonNode jsonIntent, Description description) { + // check id + final String jsonId = jsonIntent.get("id").asText(); + final String id = intent.id().toString(); + if (!jsonId.equals(id)) { + description.appendText("id was " + jsonId); + return false; + } + + // check application id + final JsonNode jsonAppIdNode = jsonIntent.get("appId"); + + final String jsonAppId = jsonAppIdNode.asText(); + final String appId = intent.appId().name(); + if (!jsonAppId.equals(appId)) { + description.appendText("appId was " + jsonAppId); + return false; + } + + // check intent type + final String jsonType = jsonIntent.get("type").asText(); + final String type = intent.getClass().getSimpleName(); + if (!jsonType.equals(type)) { + description.appendText("type was " + jsonType); + return false; + } + + // check resources array + final JsonNode jsonResources = jsonIntent.get("resources"); + if (intent.resources() != null) { + if (intent.resources().size() != jsonResources.size()) { + description.appendText("resources array size was " + + Integer.toString(jsonResources.size())); + return false; + } + for (final NetworkResource resource : intent.resources()) { + boolean resourceFound = false; + final String resourceString = resource.toString(); + for (int resourceIndex = 0; resourceIndex < jsonResources.size(); resourceIndex++) { + final JsonNode value = jsonResources.get(resourceIndex); + if (value.asText().equals(resourceString)) { + resourceFound = true; + } + } + if (!resourceFound) { + description.appendText("resource missing " + resourceString); + return false; + } + } + } else if (jsonResources.size() != 0) { + description.appendText("resources array empty"); + return false; + } + + if (intent instanceof ConnectivityIntent) { + return matchConnectivityIntent(jsonIntent, description); + } else { + description.appendText("class of intent is unknown"); + return false; + } + } + + @Override + public void describeTo(Description description) { + description.appendText(intent.toString()); + } + + /** + * Factory to allocate an intent matcher. + * + * @param intent intent object we are looking for + * @return matcher + */ + public static IntentJsonMatcher matchesIntent(Intent intent) { + return new IntentJsonMatcher(intent); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/JsonCodecUtils.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/JsonCodecUtils.java new file mode 100644 index 00000000..67c2f47f --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/JsonCodecUtils.java @@ -0,0 +1,83 @@ +/* + * 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 static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertEquals; +import static org.onosproject.net.DeviceId.deviceId; + +import org.onlab.packet.ChassisId; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.SparseAnnotations; +import org.onosproject.net.provider.ProviderId; + +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * JsonCodec test utilities. + */ +public abstract class JsonCodecUtils { + + /** + * Checks if given Object can be encoded to JSON and back. + * + * @param context CodecContext + * @param codec JsonCodec + * @param pojoIn Java Object to encode. + * Object is expected to have #equals implemented. + */ + public static void assertJsonEncodable(final CodecContext context, + final JsonCodec codec, + final T pojoIn) { + final ObjectNode json = codec.encode(pojoIn, context); + + assertThat(json, is(notNullValue())); + + final T pojoOut = codec.decode(json, context); + assertThat(pojoOut, is(notNullValue())); + + assertEquals(pojoIn, pojoOut); + } + + static final ProviderId PID = new ProviderId("of", "foo"); + static final ProviderId PIDA = new ProviderId("of", "bar", true); + static final DeviceId DID1 = deviceId("of:foo"); + static final DeviceId DID2 = deviceId("of:bar"); + static final String MFR = "whitebox"; + static final String HW = "1.1.x"; + static final String SW1 = "3.8.1"; + static final String SW2 = "3.9.5"; + static final String SN = "43311-12345"; + static final ChassisId CID = new ChassisId(); + static final PortNumber P1 = PortNumber.portNumber(1); + static final PortNumber P2 = PortNumber.portNumber(2); + static final PortNumber P3 = PortNumber.portNumber(3); + static final SparseAnnotations A1 = DefaultAnnotations.builder() + .set("A1", "a1") + .set("B1", "b1") + .build(); + static final ConnectPoint CP1 = new ConnectPoint(DID1, P1); + static final ConnectPoint CP2 = new ConnectPoint(DID2, P2); + +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/LinkCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/LinkCodecTest.java new file mode 100644 index 00000000..c44b0eb1 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/LinkCodecTest.java @@ -0,0 +1,54 @@ +/* + * 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 static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.codec.impl.JsonCodecUtils.assertJsonEncodable; + +import org.junit.Test; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.DefaultLink; +import org.onosproject.net.Link; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.device.DeviceServiceAdapter; + +/** + * Unit test for LinkCodec. + */ +public class LinkCodecTest { + + private final Link link = new DefaultLink(JsonCodecUtils.PID, + JsonCodecUtils.CP1, + JsonCodecUtils.CP2, + Link.Type.DIRECT, + Link.State.ACTIVE, + false, + JsonCodecUtils.A1); + + @Test + public void linkCodecTest() { + final MockCodecContext context = new MockCodecContext(); + context.registerService(DeviceService.class, new DeviceServiceAdapter()); + final JsonCodec codec = context.codec(Link.class); + assertThat(codec, is(notNullValue())); + final Link pojoIn = link; + + assertJsonEncodable(context, codec, pojoIn); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/LoadCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/LoadCodecTest.java new file mode 100644 index 00000000..4cb2916e --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/LoadCodecTest.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.codec.impl; + +import org.junit.Test; +import org.onosproject.net.statistic.DefaultLoad; +import org.onosproject.net.statistic.Load; + +import com.fasterxml.jackson.databind.JsonNode; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.is; + +/** + * Unit tests for Load codec. + */ +public class LoadCodecTest { + + /** + * Tests encoding of a Load object. + */ + @Test + public void testLoadEncode() { + final long startTime = System.currentTimeMillis(); + final Load load = new DefaultLoad(20, 10, 1); + final JsonNode node = new LoadCodec() + .encode(load, new MockCodecContext()); + assertThat(node.get("valid").asBoolean(), is(true)); + assertThat(node.get("latest").asLong(), is(20L)); + assertThat(node.get("rate").asLong(), is(10L)); + assertThat(node.get("time").asLong(), greaterThanOrEqualTo(startTime)); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/MockCodecContext.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/MockCodecContext.java new file mode 100644 index 00000000..6a9b6708 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/MockCodecContext.java @@ -0,0 +1,64 @@ +/* + * 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 java.util.HashMap; +import java.util.Map; + +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Mock codec context for use in codec unit tests. + */ +public class MockCodecContext implements CodecContext { + + private final ObjectMapper mapper = new ObjectMapper(); + private final CodecManager manager = new CodecManager(); + private final Map, Object> services = new HashMap<>(); + + /** + * Constructs a new mock codec context. + */ + public MockCodecContext() { + manager.activate(); + } + + @Override + public ObjectMapper mapper() { + return mapper; + } + + @Override + @SuppressWarnings("unchecked") + public JsonCodec codec(Class entityClass) { + return manager.getCodec(entityClass); + } + + @SuppressWarnings("unchecked") + @Override + public T getService(Class serviceClass) { + return (T) services.get(serviceClass); + } + + // for registering mock services + public void registerService(Class serviceClass, T impl) { + services.put(serviceClass, impl); + } + +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/PortCodecTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/PortCodecTest.java new file mode 100644 index 00000000..f3f7d920 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/codec/impl/PortCodecTest.java @@ -0,0 +1,66 @@ +/* + * 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 static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.codec.impl.JsonCodecUtils.assertJsonEncodable; + +import org.junit.Test; +import org.onosproject.codec.JsonCodec; +import org.onosproject.net.DefaultDevice; +import org.onosproject.net.DefaultPort; +import org.onosproject.net.Device; +import org.onosproject.net.Port; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.device.DeviceServiceAdapter; + +/** + * Unit test for PortCodec. + */ +public class PortCodecTest { + + + + private final Device device = new DefaultDevice(JsonCodecUtils.PID, + JsonCodecUtils.DID1, + Device.Type.SWITCH, + JsonCodecUtils.MFR, + JsonCodecUtils.HW, + JsonCodecUtils.SW1, + JsonCodecUtils.SN, + JsonCodecUtils.CID, + JsonCodecUtils.A1); + + private final Port port = new DefaultPort(device, + JsonCodecUtils.P1, + true, + JsonCodecUtils.A1); + + @Test + public void portCodecTest() { + final MockCodecContext context = new MockCodecContext(); + context.registerService(DeviceService.class, new DeviceServiceAdapter()); + final JsonCodec codec = context.codec(Port.class); + assertThat(codec, is(notNullValue())); + final Port pojoIn = port; + + assertJsonEncodable(context, codec, pojoIn); + } + +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/common/DefaultTopologyTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/common/DefaultTopologyTest.java new file mode 100644 index 00000000..4d435cfe --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/common/DefaultTopologyTest.java @@ -0,0 +1,141 @@ +/* + * Copyright 2014-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.common; + +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.ChassisId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultDevice; +import org.onosproject.net.DefaultLink; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.PortNumber; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.net.topology.ClusterId; +import org.onosproject.net.topology.DefaultGraphDescription; +import org.onosproject.net.topology.GraphDescription; +import org.onosproject.net.topology.LinkWeight; +import org.onosproject.net.topology.TopologyCluster; + +import java.util.Set; + +import static com.google.common.collect.ImmutableSet.of; +import static org.junit.Assert.*; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Test of the default topology implementation. + */ +public class DefaultTopologyTest { + + public static final ProviderId PID = new ProviderId("of", "foo.bar"); + + public static final DeviceId D1 = deviceId("of:1"); + public static final DeviceId D2 = deviceId("of:2"); + public static final DeviceId D3 = deviceId("of:3"); + public static final DeviceId D4 = deviceId("of:4"); + public static final DeviceId D5 = deviceId("of:5"); + + public static final PortNumber P1 = portNumber(1); + public static final PortNumber P2 = portNumber(2); + + public static final LinkWeight WEIGHT = edge -> + edge.src().deviceId().equals(D4) || edge.dst().deviceId().equals(D4) + ? 2.0 : 1.0; + + private DefaultTopology dt; + + @Before + public void setUp() { + long now = System.currentTimeMillis(); + Set devices = of(device("1"), device("2"), + device("3"), device("4"), + device("5")); + Set links = of(link("1", 1, "2", 1), link("2", 1, "1", 1), + link("3", 2, "2", 2), link("2", 2, "3", 2), + link("1", 3, "4", 3), link("4", 3, "1", 3), + link("3", 4, "4", 4), link("4", 4, "3", 4)); + GraphDescription graphDescription = + new DefaultGraphDescription(now, devices, links); + + dt = new DefaultTopology(PID, graphDescription); + assertEquals("incorrect supplier", PID, dt.providerId()); + assertEquals("incorrect time", now, dt.time()); + assertEquals("incorrect device count", 5, dt.deviceCount()); + assertEquals("incorrect link count", 8, dt.linkCount()); + assertEquals("incorrect cluster count", 2, dt.clusterCount()); + assertEquals("incorrect broadcast set size", 6, + dt.broadcastSetSize(ClusterId.clusterId(0))); + } + + @Test + public void pathRelated() { + Set paths = dt.getPaths(D1, D2); + assertEquals("incorrect path count", 1, paths.size()); + + paths = dt.getPaths(D1, D3); + assertEquals("incorrect path count", 2, paths.size()); + + paths = dt.getPaths(D1, D5); + assertTrue("no paths expected", paths.isEmpty()); + + paths = dt.getPaths(D1, D3, WEIGHT); + assertEquals("incorrect path count", 1, paths.size()); + } + + @Test + public void pointRelated() { + assertTrue("should be infrastructure point", + dt.isInfrastructure(new ConnectPoint(D1, P1))); + assertFalse("should not be infrastructure point", + dt.isInfrastructure(new ConnectPoint(D1, P2))); + } + + @Test + public void clusterRelated() { + Set clusters = dt.getClusters(); + assertEquals("incorrect cluster count", 2, clusters.size()); + + TopologyCluster c = dt.getCluster(D1); + Set devs = dt.getClusterDevices(c); + assertEquals("incorrect cluster device count", 4, devs.size()); + assertTrue("cluster should contain D2", devs.contains(D2)); + assertFalse("cluster should not contain D5", devs.contains(D5)); + } + + // Short-hand for creating a link. + public static Link link(String src, int sp, String dst, int dp) { + return new DefaultLink(PID, new ConnectPoint(did(src), portNumber(sp)), + new ConnectPoint(did(dst), portNumber(dp)), + Link.Type.DIRECT); + } + + // Crates a new device with the specified id + public static Device device(String id) { + return new DefaultDevice(PID, did(id), Device.Type.SWITCH, + "mfg", "1.0", "1.1", "1234", new ChassisId()); + } + + // Short-hand for producing a device id from a string + public static DeviceId did(String id) { + return deviceId("of:" + id); + } + +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/common/app/ApplicationArchiveTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/common/app/ApplicationArchiveTest.java new file mode 100644 index 00000000..97012c4e --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/common/app/ApplicationArchiveTest.java @@ -0,0 +1,157 @@ +/* + * 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.common.app; + +import com.google.common.collect.ImmutableSet; +import com.google.common.io.ByteStreams; +import com.google.common.io.Files; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onlab.util.Tools; +import org.onosproject.app.ApplicationDescription; +import org.onosproject.app.ApplicationException; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Set; + +import static org.junit.Assert.*; +import static org.onosproject.app.DefaultApplicationDescriptionTest.*; + +/** + * Suite of tests for the application archive utility. + */ +public class ApplicationArchiveTest { + + static final File STORE = Files.createTempDir(); + + private ApplicationArchive aar = new ApplicationArchive(); + + @Before + public void setUp() { + aar.setRootPath(STORE.getAbsolutePath()); + } + + @After + public void tearDown() throws IOException { + if (STORE.exists()) { + Tools.removeDirectory(STORE); + } + } + + private void validate(ApplicationDescription app) { + assertEquals("incorrect name", APP_NAME, app.name()); + assertEquals("incorrect version", VER, app.version()); + assertEquals("incorrect origin", ORIGIN, app.origin()); + assertEquals("incorrect role", ROLE, app.role()); + + assertEquals("incorrect description", DESC, app.description()); + assertEquals("incorrect features URI", FURL, app.featuresRepo().get()); + assertEquals("incorrect permissions", PERMS, app.permissions()); + assertEquals("incorrect features", FEATURES, app.features()); + } + + @Test + public void saveZippedApp() throws IOException { + InputStream stream = getClass().getResourceAsStream("app.zip"); + ApplicationDescription app = aar.saveApplication(stream); + validate(app); + stream.close(); + } + + @Test + public void savePlainApp() throws IOException { + InputStream stream = getClass().getResourceAsStream("app.xml"); + ApplicationDescription app = aar.saveApplication(stream); + validate(app); + stream.close(); + } + + @Test + public void loadApp() throws IOException { + saveZippedApp(); + ApplicationDescription app = aar.getApplicationDescription(APP_NAME); + validate(app); + } + + @Test + public void getAppNames() throws IOException { + saveZippedApp(); + Set names = aar.getApplicationNames(); + assertEquals("incorrect names", ImmutableSet.of(APP_NAME), names); + } + + @Test + public void purgeApp() throws IOException { + saveZippedApp(); + aar.purgeApplication(APP_NAME); + assertEquals("incorrect names", ImmutableSet.of(), + aar.getApplicationNames()); + } + + @Test + public void getAppZipStream() throws IOException { + saveZippedApp(); + InputStream stream = aar.getApplicationInputStream(APP_NAME); + byte[] orig = ByteStreams.toByteArray(getClass().getResourceAsStream("app.zip")); + byte[] loaded = ByteStreams.toByteArray(stream); + assertArrayEquals("incorrect stream", orig, loaded); + stream.close(); + } + + @Test + public void getAppXmlStream() throws IOException { + savePlainApp(); + InputStream stream = aar.getApplicationInputStream(APP_NAME); + byte[] orig = ByteStreams.toByteArray(getClass().getResourceAsStream("app.xml")); + byte[] loaded = ByteStreams.toByteArray(stream); + assertArrayEquals("incorrect stream", orig, loaded); + stream.close(); + } + + @Test + public void active() throws IOException { + savePlainApp(); + assertFalse("should not be active", aar.isActive(APP_NAME)); + aar.setActive(APP_NAME); + assertTrue("should not be active", aar.isActive(APP_NAME)); + aar.clearActive(APP_NAME); + assertFalse("should not be active", aar.isActive(APP_NAME)); + } + + @Test(expected = ApplicationException.class) + public void getBadAppDesc() throws IOException { + aar.getApplicationDescription("org.foo.BAD"); + } + + @Test(expected = ApplicationException.class) + public void getBadAppStream() throws IOException { + aar.getApplicationInputStream("org.foo.BAD"); + } + + @Test(expected = ApplicationException.class) + public void setBadActive() throws IOException { + aar.setActive("org.foo.BAD"); + } + + @Test // (expected = ApplicationException.class) + public void purgeBadApp() throws IOException { + aar.purgeApplication("org.foo.BAD"); + } + +} \ No newline at end of file diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/common/event/impl/TestEventDispatcher.java b/framework/src/onos/core/common/src/test/java/org/onosproject/common/event/impl/TestEventDispatcher.java new file mode 100644 index 00000000..4ea371a0 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/common/event/impl/TestEventDispatcher.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014-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.common.event.impl; + +import org.onosproject.event.DefaultEventSinkRegistry; +import org.onosproject.event.Event; +import org.onosproject.event.EventDeliveryService; +import org.onosproject.event.EventSink; + +import static com.google.common.base.Preconditions.checkState; + +/** + * Implements event delivery system that delivers events synchronously, or + * in-line with the post method invocation. + */ +public class TestEventDispatcher extends DefaultEventSinkRegistry + implements EventDeliveryService { + + @Override + @SuppressWarnings("unchecked") + public synchronized void post(Event event) { + EventSink sink = getSink(event.getClass()); + checkState(sink != null, "No sink for event %s", event); + sink.process(event); + } + + @Override + public void setDispatchTimeLimit(long millis) { + } + + @Override + public long getDispatchTimeLimit() { + return 0; + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/PathKey.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/PathKey.java new file mode 100644 index 00000000..00d6c9d2 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/PathKey.java @@ -0,0 +1,55 @@ +/* + * Copyright 2014 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.trivial; + +import org.onosproject.net.DeviceId; + +import java.util.Objects; + +/** + * Key for filing pre-computed paths between source and destination devices. + */ +class PathKey { + private final DeviceId src; + private final DeviceId dst; + + /** + * Creates a path key from the given source/dest pair. + * @param src source device + * @param dst destination device + */ + PathKey(DeviceId src, DeviceId dst) { + this.src = src; + this.dst = dst; + } + + @Override + public int hashCode() { + return Objects.hash(src, dst); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof PathKey) { + final PathKey other = (PathKey) obj; + return Objects.equals(this.src, other.src) && Objects.equals(this.dst, other.dst); + } + return false; + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationIdStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationIdStore.java new file mode 100644 index 00000000..6e6b9587 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationIdStore.java @@ -0,0 +1,70 @@ +/* + * Copyright 2014-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.trivial; + +import com.google.common.collect.ImmutableSet; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Service; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.ApplicationIdStore; +import org.onosproject.core.DefaultApplicationId; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Simple implementation of the application ID registry using in-memory + * structures. + */ +@Component(immediate = true) +@Service +public class SimpleApplicationIdStore implements ApplicationIdStore { + + private static final AtomicInteger ID_DISPENSER = new AtomicInteger(1); + + private final Map appIds = new ConcurrentHashMap<>(); + private final Map appIdsByName = new ConcurrentHashMap<>(); + + @Override + public Set getAppIds() { + return ImmutableSet.copyOf(appIds.values()); + } + + @Override + public ApplicationId getAppId(Short id) { + return appIds.get(id); + } + + @Override + public ApplicationId getAppId(String name) { + return appIdsByName.get(name); + } + + @Override + public ApplicationId registerApplication(String name) { + DefaultApplicationId appId = appIdsByName.get(name); + if (appId == null) { + short id = (short) ID_DISPENSER.getAndIncrement(); + appId = new DefaultApplicationId(id, name); + appIds.put(id, appId); + appIdsByName.put(name, appId); + } + return appId; + } + +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationStore.java new file mode 100644 index 00000000..ea9a773e --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationStore.java @@ -0,0 +1,170 @@ +/* + * 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.trivial; + +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.app.ApplicationDescription; +import org.onosproject.app.ApplicationEvent; +import org.onosproject.app.ApplicationState; +import org.onosproject.app.ApplicationStore; +import org.onosproject.common.app.ApplicationArchive; +import org.onosproject.core.Application; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.ApplicationIdStore; +import org.onosproject.core.DefaultApplication; +import org.onosproject.security.Permission; +import org.slf4j.Logger; + +import java.io.InputStream; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static org.onosproject.app.ApplicationEvent.Type.*; +import static org.onosproject.app.ApplicationState.ACTIVE; +import static org.onosproject.app.ApplicationState.INSTALLED; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Manages inventory of network control applications. + */ +@Component(immediate = true) +@Service +public class SimpleApplicationStore extends ApplicationArchive implements ApplicationStore { + + private final Logger log = getLogger(getClass()); + + // App inventory & states + private final ConcurrentMap apps = new ConcurrentHashMap<>(); + private final ConcurrentMap states = new ConcurrentHashMap<>(); + private final ConcurrentMap> permissions = new ConcurrentHashMap<>(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ApplicationIdStore idStore; + + @Activate + public void activate() { + loadFromDisk(); + log.info("Started"); + } + + private void loadFromDisk() { + for (String name : getApplicationNames()) { + ApplicationId appId = idStore.registerApplication(name); + ApplicationDescription appDesc = getApplicationDescription(name); + DefaultApplication app = + new DefaultApplication(appId, appDesc.version(), + appDesc.description(), appDesc.origin(), + appDesc.role(), appDesc.permissions(), + appDesc.featuresRepo(), appDesc.features()); + apps.put(appId, app); + states.put(appId, isActive(name) ? INSTALLED : ACTIVE); + // load app permissions + } + } + + @Deactivate + public void deactivate() { + apps.clear(); + states.clear(); + permissions.clear(); + log.info("Stopped"); + } + + @Override + public Set getApplications() { + return ImmutableSet.copyOf(apps.values()); + } + + @Override + public ApplicationId getId(String name) { + return idStore.getAppId(name); + } + + @Override + public Application getApplication(ApplicationId appId) { + return apps.get(appId); + } + + @Override + public ApplicationState getState(ApplicationId appId) { + return states.get(appId); + } + + @Override + public Application create(InputStream appDescStream) { + ApplicationDescription appDesc = saveApplication(appDescStream); + ApplicationId appId = idStore.registerApplication(appDesc.name()); + DefaultApplication app = + new DefaultApplication(appId, appDesc.version(), appDesc.description(), + appDesc.origin(), appDesc.role(), appDesc.permissions(), + appDesc.featuresRepo(), appDesc.features()); + apps.put(appId, app); + states.put(appId, INSTALLED); + delegate.notify(new ApplicationEvent(APP_INSTALLED, app)); + return app; + } + + @Override + public void remove(ApplicationId appId) { + Application app = apps.remove(appId); + if (app != null) { + states.remove(appId); + delegate.notify(new ApplicationEvent(APP_UNINSTALLED, app)); + purgeApplication(app.id().name()); + } + } + + @Override + public void activate(ApplicationId appId) { + Application app = apps.get(appId); + if (app != null) { + setActive(appId.name()); + states.put(appId, ACTIVE); + delegate.notify(new ApplicationEvent(APP_ACTIVATED, app)); + } + } + + @Override + public void deactivate(ApplicationId appId) { + Application app = apps.get(appId); + if (app != null) { + clearActive(appId.name()); + states.put(appId, INSTALLED); + delegate.notify(new ApplicationEvent(APP_DEACTIVATED, app)); + } + } + + @Override + public Set getPermissions(ApplicationId appId) { + return permissions.get(appId); + } + + @Override + public void setPermissions(ApplicationId appId, Set permissions) { + Application app = getApplication(appId); + if (app != null) { + this.permissions.put(appId, permissions); + delegate.notify(new ApplicationEvent(APP_PERMISSIONS_CHANGED, app)); + } + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationStoreTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationStoreTest.java new file mode 100644 index 00000000..a1c7da37 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleApplicationStoreTest.java @@ -0,0 +1,154 @@ +/* + * 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.trivial; + +import com.google.common.collect.ImmutableSet; +import com.google.common.io.Files; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onlab.util.Tools; +import org.onosproject.app.ApplicationEvent; +import org.onosproject.app.ApplicationStoreDelegate; +import org.onosproject.common.app.ApplicationArchive; +import org.onosproject.core.Application; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.ApplicationIdStoreAdapter; +import org.onosproject.core.DefaultApplicationId; +import org.onosproject.security.AppPermission; +import org.onosproject.security.Permission; + +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.app.ApplicationEvent.Type.*; +import static org.onosproject.app.ApplicationState.ACTIVE; +import static org.onosproject.app.ApplicationState.INSTALLED; + +/** + * Test of the trivial application store implementation. + */ +public class SimpleApplicationStoreTest { + + static final File STORE = Files.createTempDir(); + + private TestApplicationStore store = new TestApplicationStore(); + private TestDelegate delegate = new TestDelegate(); + private static final Object LOCK = new Object(); + + @Before + public void setUp() { + store.idStore = new TestIdStore(); + store.setRootPath(STORE.getAbsolutePath()); + store.setDelegate(delegate); + store.activate(); + } + + @After + public void tearDown() throws IOException { + if (STORE.exists()) { + Tools.removeDirectory(STORE); + } + store.deactivate(); + } + + private Application createTestApp() { + synchronized (LOCK) { + return store.create(ApplicationArchive.class.getResourceAsStream("app.zip")); + } + } + + @Test + public void create() { + Application app = createTestApp(); + assertEquals("incorrect name", "org.foo.app", app.id().name()); + assertEquals("incorrect app count", 1, store.getApplications().size()); + assertEquals("incorrect app", app, store.getApplication(app.id())); + assertEquals("incorrect app state", INSTALLED, store.getState(app.id())); + assertEquals("incorrect event type", APP_INSTALLED, delegate.event.type()); + assertEquals("incorrect event app", app, delegate.event.subject()); + } + + @Test + public void remove() { + Application app = createTestApp(); + store.remove(app.id()); + assertEquals("incorrect app count", 0, store.getApplications().size()); + assertEquals("incorrect event type", APP_UNINSTALLED, delegate.event.type()); + assertEquals("incorrect event app", app, delegate.event.subject()); + } + + @Test + public void activate() { + Application app = createTestApp(); + store.activate(app.id()); + assertEquals("incorrect app count", 1, store.getApplications().size()); + assertEquals("incorrect app state", ACTIVE, store.getState(app.id())); + assertEquals("incorrect event type", APP_ACTIVATED, delegate.event.type()); + assertEquals("incorrect event app", app, delegate.event.subject()); + } + + @Test + public void deactivate() { + Application app = createTestApp(); + store.deactivate(app.id()); + assertEquals("incorrect app count", 1, store.getApplications().size()); + assertEquals("incorrect app state", INSTALLED, store.getState(app.id())); + assertEquals("incorrect event type", APP_DEACTIVATED, delegate.event.type()); + assertEquals("incorrect event app", app, delegate.event.subject()); + } + + @Test + public void permissions() { + Application app = createTestApp(); + ImmutableSet permissions = + ImmutableSet.of(new Permission(AppPermission.class.getName(), "FLOWRULE_WRITE")); + store.setPermissions(app.id(), permissions); + assertEquals("incorrect app perms", 1, store.getPermissions(app.id()).size()); + assertEquals("incorrect app state", INSTALLED, store.getState(app.id())); + assertEquals("incorrect event type", APP_PERMISSIONS_CHANGED, delegate.event.type()); + assertEquals("incorrect event app", app, delegate.event.subject()); + } + + private class TestIdStore extends ApplicationIdStoreAdapter { + @Override + public ApplicationId registerApplication(String name) { + return new DefaultApplicationId(1, name); + } + + @Override + public ApplicationId getAppId(String name) { + return new DefaultApplicationId(1, name); + } + } + + private class TestDelegate implements ApplicationStoreDelegate { + private ApplicationEvent event; + + @Override + public void notify(ApplicationEvent event) { + this.event = event; + } + } + + private class TestApplicationStore extends SimpleApplicationStore { + @Override + public void setRootPath(String root) { + super.setRootPath(root); + } + } +} \ No newline at end of file diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleClusterStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleClusterStore.java new file mode 100644 index 00000000..5eea3cc8 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleClusterStore.java @@ -0,0 +1,139 @@ +/* + * Copyright 2014-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.trivial; + +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.joda.time.DateTime; +import org.onlab.packet.IpAddress; +import org.onosproject.cluster.ClusterEvent; +import org.onosproject.cluster.ClusterStore; +import org.onosproject.cluster.ClusterStoreDelegate; +import org.onosproject.cluster.ControllerNode; +import org.onosproject.cluster.DefaultControllerNode; +import org.onosproject.cluster.NodeId; +import org.onosproject.event.EventDeliveryService; +import org.onosproject.event.ListenerRegistry; +import org.onosproject.net.intent.Key; +import org.onosproject.net.intent.PartitionEvent; +import org.onosproject.net.intent.PartitionEventListener; +import org.onosproject.net.intent.PartitionService; +import org.onosproject.store.AbstractStore; +import org.slf4j.Logger; + +import java.util.Set; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Manages inventory of infrastructure devices using trivial in-memory + * structures implementation. + */ +@Component(immediate = true) +@Service +public class SimpleClusterStore + extends AbstractStore + implements ClusterStore, PartitionService { + + public static final IpAddress LOCALHOST = IpAddress.valueOf("127.0.0.1"); + + private final Logger log = getLogger(getClass()); + + private ControllerNode instance; + + private final DateTime creationTime = DateTime.now(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected EventDeliveryService eventDispatcher; + + private ListenerRegistry listenerRegistry; + + @Activate + public void activate() { + instance = new DefaultControllerNode(new NodeId("local"), LOCALHOST); + + listenerRegistry = new ListenerRegistry<>(); + eventDispatcher.addSink(PartitionEvent.class, listenerRegistry); + + log.info("Started"); + } + + @Deactivate + public void deactivate() { + eventDispatcher.removeSink(PartitionEvent.class); + log.info("Stopped"); + } + + + @Override + public ControllerNode getLocalNode() { + return instance; + } + + @Override + public Set getNodes() { + return ImmutableSet.of(instance); + } + + @Override + public ControllerNode getNode(NodeId nodeId) { + return instance.id().equals(nodeId) ? instance : null; + } + + @Override + public ControllerNode.State getState(NodeId nodeId) { + return ControllerNode.State.ACTIVE; + } + + @Override + public DateTime getLastUpdated(NodeId nodeId) { + return creationTime; + } + + @Override + public ControllerNode addNode(NodeId nodeId, IpAddress ip, int tcpPort) { + return null; + } + + @Override + public void removeNode(NodeId nodeId) { + } + + @Override + public boolean isMine(Key intentKey) { + return true; + } + + @Override + public NodeId getLeader(Key intentKey) { + return instance.id(); + } + + @Override + public void addListener(PartitionEventListener listener) { + listenerRegistry.addListener(listener); + } + + @Override + public void removeListener(PartitionEventListener listener) { + listenerRegistry.removeListener(listener); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleComponentConfigStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleComponentConfigStore.java new file mode 100644 index 00000000..1d8bcd62 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleComponentConfigStore.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.store.trivial; + +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.Service; +import org.onosproject.cfg.ComponentConfigEvent; +import org.onosproject.cfg.ComponentConfigStore; +import org.onosproject.cfg.ComponentConfigStoreDelegate; +import org.onosproject.store.AbstractStore; +import org.slf4j.Logger; + +import static org.onosproject.cfg.ComponentConfigEvent.Type.PROPERTY_SET; +import static org.onosproject.cfg.ComponentConfigEvent.Type.PROPERTY_UNSET; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Manages inventory of component configuration properties. + */ +@Component(immediate = true) +@Service +public class SimpleComponentConfigStore + extends AbstractStore + implements ComponentConfigStore { + + private final Logger log = getLogger(getClass()); + + @Activate + public void activate() { + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + + @Override + public void setProperty(String componentName, String name, String value) { + delegate.notify(new ComponentConfigEvent(PROPERTY_SET, componentName, name, value)); + } + + @Override + public void unsetProperty(String componentName, String name) { + delegate.notify(new ComponentConfigEvent(PROPERTY_UNSET, componentName, name, null)); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleDeviceStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleDeviceStore.java new file mode 100644 index 00000000..fc90dfad --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleDeviceStore.java @@ -0,0 +1,691 @@ +/* + * Copyright 2014-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.trivial; + +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Maps; +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; +import org.apache.felix.scr.annotations.Service; +import org.onosproject.net.AnnotationsUtil; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.DefaultDevice; +import org.onosproject.net.DefaultPort; +import org.onosproject.net.Device; +import org.onosproject.net.Device.Type; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.SparseAnnotations; +import org.onosproject.net.device.DefaultDeviceDescription; +import org.onosproject.net.device.DefaultPortDescription; +import org.onosproject.net.device.DefaultPortStatistics; +import org.onosproject.net.device.DeviceDescription; +import org.onosproject.net.device.DeviceEvent; +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.ProviderId; +import org.onosproject.store.AbstractStore; +import org.onlab.packet.ChassisId; +import org.onlab.util.NewConcurrentHashMap; +import org.slf4j.Logger; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Predicates.notNull; +import static com.google.common.base.Verify.verify; +import static org.onosproject.net.device.DeviceEvent.Type.*; +import static org.slf4j.LoggerFactory.getLogger; +import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; +import static org.onosproject.net.DefaultAnnotations.union; +import static org.onosproject.net.DefaultAnnotations.merge; + +/** + * Manages inventory of infrastructure devices using trivial in-memory + * structures implementation. + */ +@Component(immediate = true) +@Service +public class SimpleDeviceStore + extends AbstractStore + implements DeviceStore { + + private final Logger log = getLogger(getClass()); + + public static final String DEVICE_NOT_FOUND = "Device with ID %s not found"; + + // Collection of Description given from various providers + private final ConcurrentMap> + deviceDescs = Maps.newConcurrentMap(); + + // Cache of Device and Ports generated by compositing descriptions from providers + private final ConcurrentMap devices = Maps.newConcurrentMap(); + private final ConcurrentMap> + devicePorts = Maps.newConcurrentMap(); + private final ConcurrentMap> + devicePortStats = Maps.newConcurrentMap(); + private final ConcurrentMap> + devicePortDeltaStats = Maps.newConcurrentMap(); + + // Available (=UP) devices + private final Set availableDevices = Sets.newConcurrentHashSet(); + + + @Activate + public void activate() { + log.info("Started"); + } + + @Deactivate + public void deactivate() { + deviceDescs.clear(); + devices.clear(); + devicePorts.clear(); + availableDevices.clear(); + log.info("Stopped"); + } + + @Override + public int getDeviceCount() { + return devices.size(); + } + + @Override + public Iterable getDevices() { + return Collections.unmodifiableCollection(devices.values()); + } + + @Override + public Iterable getAvailableDevices() { + return FluentIterable.from(getDevices()) + .filter(new Predicate() { + + @Override + public boolean apply(Device input) { + return isAvailable(input.id()); + } + }); + } + + @Override + public Device getDevice(DeviceId deviceId) { + return devices.get(deviceId); + } + + @Override + public DeviceEvent createOrUpdateDevice(ProviderId providerId, + DeviceId deviceId, + DeviceDescription deviceDescription) { + Map providerDescs + = getOrCreateDeviceDescriptions(deviceId); + + synchronized (providerDescs) { + // locking per device + DeviceDescriptions descs + = getOrCreateProviderDeviceDescriptions(providerDescs, + providerId, + deviceDescription); + + Device oldDevice = devices.get(deviceId); + // update description + descs.putDeviceDesc(deviceDescription); + Device newDevice = composeDevice(deviceId, providerDescs); + + if (oldDevice == null) { + // ADD + return createDevice(providerId, newDevice); + } else { + // UPDATE or ignore (no change or stale) + return updateDevice(providerId, oldDevice, newDevice); + } + } + } + + // Creates the device and returns the appropriate event if necessary. + // Guarded by deviceDescs value (=Device lock) + private DeviceEvent createDevice(ProviderId providerId, Device newDevice) { + // update composed device cache + Device oldDevice = devices.putIfAbsent(newDevice.id(), newDevice); + verify(oldDevice == null, + "Unexpected Device in cache. PID:%s [old=%s, new=%s]", + providerId, oldDevice, newDevice); + + if (!providerId.isAncillary()) { + availableDevices.add(newDevice.id()); + } + + return new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, newDevice, null); + } + + // Updates the device and returns the appropriate event if necessary. + // Guarded by deviceDescs value (=Device lock) + private DeviceEvent updateDevice(ProviderId providerId, Device oldDevice, Device newDevice) { + // We allow only certain attributes to trigger update + boolean propertiesChanged = + !Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) || + !Objects.equals(oldDevice.swVersion(), newDevice.swVersion()); + boolean annotationsChanged = + !AnnotationsUtil.isEqual(oldDevice.annotations(), newDevice.annotations()); + + // Primary providers can respond to all changes, but ancillary ones + // should respond only to annotation changes. + if ((providerId.isAncillary() && annotationsChanged) || + (!providerId.isAncillary() && (propertiesChanged || annotationsChanged))) { + + boolean replaced = devices.replace(newDevice.id(), oldDevice, newDevice); + if (!replaced) { + // FIXME: Is the enclosing if required here? + verify(replaced, + "Replacing devices cache failed. PID:%s [expected:%s, found:%s, new=%s]", + providerId, oldDevice, devices.get(newDevice.id()) + , newDevice); + } + if (!providerId.isAncillary()) { + availableDevices.add(newDevice.id()); + } + return new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, newDevice, null); + } + + // Otherwise merely attempt to change availability if primary provider + if (!providerId.isAncillary()) { + boolean added = availableDevices.add(newDevice.id()); + return !added ? null : + new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, newDevice, null); + } + return null; + } + + @Override + public DeviceEvent markOffline(DeviceId deviceId) { + Map providerDescs + = getOrCreateDeviceDescriptions(deviceId); + + // locking device + synchronized (providerDescs) { + Device device = devices.get(deviceId); + if (device == null) { + return null; + } + boolean removed = availableDevices.remove(deviceId); + if (removed) { + // TODO: broadcast ... DOWN only? + return new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device, null); + } + return null; + } + } + + @Override + public List updatePorts(ProviderId providerId, + DeviceId deviceId, + List portDescriptions) { + Device device = devices.get(deviceId); + if (device == null) { + log.debug("Device {} doesn't exist or hasn't been initialized yet", deviceId); + return Collections.emptyList(); + } + + Map descsMap = deviceDescs.get(deviceId); + checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId); + + List events = new ArrayList<>(); + synchronized (descsMap) { + DeviceDescriptions descs = descsMap.get(providerId); + // every provider must provide DeviceDescription. + checkArgument(descs != null, + "Device description for Device ID %s from Provider %s was not found", + deviceId, providerId); + + Map ports = getPortMap(deviceId); + + // Add new ports + Set processed = new HashSet<>(); + for (PortDescription portDescription : portDescriptions) { + final PortNumber number = portDescription.portNumber(); + processed.add(portDescription.portNumber()); + + final Port oldPort = ports.get(number); + final Port newPort; + +// event suppression hook? + + // update description + descs.putPortDesc(portDescription); + newPort = composePort(device, number, descsMap); + + events.add(oldPort == null ? + createPort(device, newPort, ports) : + updatePort(device, oldPort, newPort, ports)); + } + + events.addAll(pruneOldPorts(device, ports, processed)); + } + return FluentIterable.from(events).filter(notNull()).toList(); + } + + // Creates a new port based on the port description adds it to the map and + // Returns corresponding event. + // Guarded by deviceDescs value (=Device lock) + private DeviceEvent createPort(Device device, Port newPort, + Map ports) { + ports.put(newPort.number(), newPort); + return new DeviceEvent(PORT_ADDED, device, newPort); + } + + // Checks if the specified port requires update and if so, it replaces the + // existing entry in the map and returns corresponding event. + // Guarded by deviceDescs value (=Device lock) + private DeviceEvent updatePort(Device device, Port oldPort, + Port newPort, + Map ports) { + if (oldPort.isEnabled() != newPort.isEnabled() || + oldPort.type() != newPort.type() || + oldPort.portSpeed() != newPort.portSpeed() || + !AnnotationsUtil.isEqual(oldPort.annotations(), newPort.annotations())) { + ports.put(oldPort.number(), newPort); + return new DeviceEvent(PORT_UPDATED, device, newPort); + } + return null; + } + + // Prunes the specified list of ports based on which ports are in the + // processed list and returns list of corresponding events. + // Guarded by deviceDescs value (=Device lock) + private List pruneOldPorts(Device device, + Map ports, + Set processed) { + List events = new ArrayList<>(); + Iterator> iterator = ports.entrySet().iterator(); + while (iterator.hasNext()) { + Entry e = iterator.next(); + PortNumber portNumber = e.getKey(); + if (!processed.contains(portNumber)) { + events.add(new DeviceEvent(PORT_REMOVED, device, e.getValue())); + iterator.remove(); + } + } + return events; + } + + // Gets the map of ports for the specified device; if one does not already + // exist, it creates and registers a new one. + private ConcurrentMap getPortMap(DeviceId deviceId) { + return createIfAbsentUnchecked(devicePorts, deviceId, + NewConcurrentHashMap.ifNeeded()); + } + + private Map getOrCreateDeviceDescriptions( + DeviceId deviceId) { + Map r; + r = deviceDescs.get(deviceId); + if (r != null) { + return r; + } + r = new HashMap<>(); + final Map concurrentlyAdded; + concurrentlyAdded = deviceDescs.putIfAbsent(deviceId, r); + if (concurrentlyAdded != null) { + return concurrentlyAdded; + } else { + return r; + } + } + + // Guarded by deviceDescs value (=Device lock) + private DeviceDescriptions getOrCreateProviderDeviceDescriptions( + Map device, + ProviderId providerId, DeviceDescription deltaDesc) { + synchronized (device) { + DeviceDescriptions r = device.get(providerId); + if (r == null) { + r = new DeviceDescriptions(deltaDesc); + device.put(providerId, r); + } + return r; + } + } + + @Override + public DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId, + PortDescription portDescription) { + Device device = devices.get(deviceId); + checkArgument(device != null, DEVICE_NOT_FOUND, deviceId); + + Map descsMap = deviceDescs.get(deviceId); + checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId); + + synchronized (descsMap) { + DeviceDescriptions descs = descsMap.get(providerId); + // assuming all providers must give DeviceDescription first + checkArgument(descs != null, + "Device description for Device ID %s from Provider %s was not found", + deviceId, providerId); + + ConcurrentMap ports = getPortMap(deviceId); + final PortNumber number = portDescription.portNumber(); + final Port oldPort = ports.get(number); + final Port newPort; + + // update description + descs.putPortDesc(portDescription); + newPort = composePort(device, number, descsMap); + + if (oldPort == null) { + return createPort(device, newPort, ports); + } else { + return updatePort(device, oldPort, newPort, ports); + } + } + } + + @Override + public List getPorts(DeviceId deviceId) { + Map ports = devicePorts.get(deviceId); + if (ports == null) { + return Collections.emptyList(); + } + return ImmutableList.copyOf(ports.values()); + } + + @Override + public DeviceEvent updatePortStatistics(ProviderId providerId, DeviceId deviceId, + Collection newStatsCollection) { + + ConcurrentMap prvStatsMap = devicePortStats.get(deviceId); + ConcurrentMap newStatsMap = Maps.newConcurrentMap(); + ConcurrentMap deltaStatsMap = Maps.newConcurrentMap(); + + if (prvStatsMap != null) { + for (PortStatistics newStats : newStatsCollection) { + PortNumber port = PortNumber.portNumber(newStats.port()); + PortStatistics prvStats = prvStatsMap.get(port); + DefaultPortStatistics.Builder builder = DefaultPortStatistics.builder(); + PortStatistics deltaStats = builder.build(); + if (prvStats != null) { + deltaStats = calcDeltaStats(deviceId, prvStats, newStats); + } + deltaStatsMap.put(port, deltaStats); + newStatsMap.put(port, newStats); + } + } else { + for (PortStatistics newStats : newStatsCollection) { + PortNumber port = PortNumber.portNumber(newStats.port()); + newStatsMap.put(port, newStats); + } + } + devicePortDeltaStats.put(deviceId, deltaStatsMap); + devicePortStats.put(deviceId, newStatsMap); + return new DeviceEvent(PORT_STATS_UPDATED, devices.get(deviceId), null); + } + + public PortStatistics calcDeltaStats(DeviceId deviceId, PortStatistics prvStats, PortStatistics newStats) { + // calculate time difference + long deltaStatsSec, deltaStatsNano; + if (newStats.durationNano() < prvStats.durationNano()) { + deltaStatsNano = newStats.durationNano() - prvStats.durationNano() + TimeUnit.SECONDS.toNanos(1); + deltaStatsSec = newStats.durationSec() - prvStats.durationSec() - 1L; + } else { + deltaStatsNano = newStats.durationNano() - prvStats.durationNano(); + deltaStatsSec = newStats.durationSec() - prvStats.durationSec(); + } + DefaultPortStatistics.Builder builder = DefaultPortStatistics.builder(); + DefaultPortStatistics deltaStats = builder.setDeviceId(deviceId) + .setPort(newStats.port()) + .setPacketsReceived(newStats.packetsReceived() - prvStats.packetsReceived()) + .setPacketsSent(newStats.packetsSent() - prvStats.packetsSent()) + .setBytesReceived(newStats.bytesReceived() - prvStats.bytesReceived()) + .setBytesSent(newStats.bytesSent() - prvStats.bytesSent()) + .setPacketsRxDropped(newStats.packetsRxDropped() - prvStats.packetsRxDropped()) + .setPacketsTxDropped(newStats.packetsTxDropped() - prvStats.packetsTxDropped()) + .setPacketsRxErrors(newStats.packetsRxErrors() - prvStats.packetsRxErrors()) + .setPacketsTxErrors(newStats.packetsTxErrors() - prvStats.packetsTxErrors()) + .setDurationSec(deltaStatsSec) + .setDurationNano(deltaStatsNano) + .build(); + return deltaStats; + } + + @Override + public Port getPort(DeviceId deviceId, PortNumber portNumber) { + Map ports = devicePorts.get(deviceId); + return ports == null ? null : ports.get(portNumber); + } + + @Override + public List getPortStatistics(DeviceId deviceId) { + Map portStats = devicePortStats.get(deviceId); + if (portStats == null) { + return Collections.emptyList(); + } + return ImmutableList.copyOf(portStats.values()); + } + + @Override + public List getPortDeltaStatistics(DeviceId deviceId) { + Map portStats = devicePortDeltaStats.get(deviceId); + if (portStats == null) { + return Collections.emptyList(); + } + return ImmutableList.copyOf(portStats.values()); + } + + @Override + public boolean isAvailable(DeviceId deviceId) { + return availableDevices.contains(deviceId); + } + + @Override + public DeviceEvent removeDevice(DeviceId deviceId) { + Map descs = getOrCreateDeviceDescriptions(deviceId); + synchronized (descs) { + Device device = devices.remove(deviceId); + // should DEVICE_REMOVED carry removed ports? + Map ports = devicePorts.get(deviceId); + if (ports != null) { + ports.clear(); + } + availableDevices.remove(deviceId); + descs.clear(); + return device == null ? null : + new DeviceEvent(DEVICE_REMOVED, device, null); + } + } + + /** + * Returns a Device, merging description given from multiple Providers. + * + * @param deviceId device identifier + * @param providerDescs Collection of Descriptions from multiple providers + * @return Device instance + */ + private Device composeDevice(DeviceId deviceId, + Map providerDescs) { + + checkArgument(!providerDescs.isEmpty(), "No Device descriptions supplied"); + + ProviderId primary = pickPrimaryPID(providerDescs); + + DeviceDescriptions desc = providerDescs.get(primary); + + final DeviceDescription base = desc.getDeviceDesc(); + Type type = base.type(); + String manufacturer = base.manufacturer(); + String hwVersion = base.hwVersion(); + String swVersion = base.swVersion(); + String serialNumber = base.serialNumber(); + ChassisId chassisId = base.chassisId(); + DefaultAnnotations annotations = DefaultAnnotations.builder().build(); + annotations = merge(annotations, base.annotations()); + + for (Entry e : providerDescs.entrySet()) { + if (e.getKey().equals(primary)) { + continue; + } + // TODO: should keep track of Description timestamp + // and only merge conflicting keys when timestamp is newer + // Currently assuming there will never be a key conflict between + // providers + + // annotation merging. not so efficient, should revisit later + annotations = merge(annotations, e.getValue().getDeviceDesc().annotations()); + } + + return new DefaultDevice(primary, deviceId, type, manufacturer, + hwVersion, swVersion, serialNumber, + chassisId, annotations); + } + + /** + * Returns a Port, merging description given from multiple Providers. + * + * @param device device the port is on + * @param number port number + * @param descsMap Collection of Descriptions from multiple providers + * @return Port instance + */ + private Port composePort(Device device, PortNumber number, + Map descsMap) { + + ProviderId primary = pickPrimaryPID(descsMap); + DeviceDescriptions primDescs = descsMap.get(primary); + // if no primary, assume not enabled + // TODO: revisit this default port enabled/disabled behavior + boolean isEnabled = false; + DefaultAnnotations annotations = DefaultAnnotations.builder().build(); + + final PortDescription portDesc = primDescs.getPortDesc(number); + if (portDesc != null) { + isEnabled = portDesc.isEnabled(); + annotations = merge(annotations, portDesc.annotations()); + } + + for (Entry e : descsMap.entrySet()) { + if (e.getKey().equals(primary)) { + continue; + } + // TODO: should keep track of Description timestamp + // and only merge conflicting keys when timestamp is newer + // Currently assuming there will never be a key conflict between + // providers + + // annotation merging. not so efficient, should revisit later + final PortDescription otherPortDesc = e.getValue().getPortDesc(number); + if (otherPortDesc != null) { + annotations = merge(annotations, otherPortDesc.annotations()); + } + } + + return portDesc == null ? + new DefaultPort(device, number, false, annotations) : + new DefaultPort(device, number, isEnabled, portDesc.type(), + portDesc.portSpeed(), annotations); + } + + /** + * @return primary ProviderID, or randomly chosen one if none exists + */ + private ProviderId pickPrimaryPID(Map descsMap) { + ProviderId fallBackPrimary = null; + for (Entry e : descsMap.entrySet()) { + if (!e.getKey().isAncillary()) { + return e.getKey(); + } else if (fallBackPrimary == null) { + // pick randomly as a fallback in case there is no primary + fallBackPrimary = e.getKey(); + } + } + return fallBackPrimary; + } + + /** + * Collection of Description of a Device and it's Ports given from a Provider. + */ + private static class DeviceDescriptions { + + private final AtomicReference deviceDesc; + private final ConcurrentMap portDescs; + + public DeviceDescriptions(DeviceDescription desc) { + this.deviceDesc = new AtomicReference<>(checkNotNull(desc)); + this.portDescs = new ConcurrentHashMap<>(); + } + + public DeviceDescription getDeviceDesc() { + return deviceDesc.get(); + } + + public PortDescription getPortDesc(PortNumber number) { + return portDescs.get(number); + } + + /** + * Puts DeviceDescription, merging annotations as necessary. + * + * @param newDesc new DeviceDescription + * @return previous DeviceDescription + */ + public synchronized DeviceDescription putDeviceDesc(DeviceDescription newDesc) { + DeviceDescription oldOne = deviceDesc.get(); + DeviceDescription newOne = newDesc; + if (oldOne != null) { + SparseAnnotations merged = union(oldOne.annotations(), + newDesc.annotations()); + newOne = new DefaultDeviceDescription(newOne, merged); + } + return deviceDesc.getAndSet(newOne); + } + + /** + * Puts PortDescription, merging annotations as necessary. + * + * @param newDesc new PortDescription + * @return previous PortDescription + */ + public synchronized PortDescription putPortDesc(PortDescription newDesc) { + PortDescription oldOne = portDescs.get(newDesc.portNumber()); + PortDescription newOne = newDesc; + if (oldOne != null) { + SparseAnnotations merged = union(oldOne.annotations(), + newDesc.annotations()); + newOne = new DefaultPortDescription(newOne, merged); + } + return portDescs.put(newOne.portNumber(), newOne); + } + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleDeviceStoreTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleDeviceStoreTest.java new file mode 100644 index 00000000..562e6f3c --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleDeviceStoreTest.java @@ -0,0 +1,530 @@ +/* + * Copyright 2014 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.trivial; + +import static org.junit.Assert.*; +import static org.onosproject.net.Device.Type.SWITCH; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.device.DeviceEvent.Type.*; +import static org.onosproject.net.NetTestTools.assertAnnotationsEquals; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.SparseAnnotations; +import org.onosproject.net.device.DefaultDeviceDescription; +import org.onosproject.net.device.DefaultPortDescription; +import org.onosproject.net.device.DeviceDescription; +import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceStore; +import org.onosproject.net.device.DeviceStoreDelegate; +import org.onosproject.net.device.PortDescription; +import org.onosproject.net.provider.ProviderId; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; + +import org.onlab.packet.ChassisId; + +/** + * Test of the simple DeviceStore implementation. + */ +public class SimpleDeviceStoreTest { + + private static final ProviderId PID = new ProviderId("of", "foo"); + private static final ProviderId PIDA = new ProviderId("of", "bar", true); + private static final DeviceId DID1 = deviceId("of:foo"); + private static final DeviceId DID2 = deviceId("of:bar"); + private static final String MFR = "whitebox"; + private static final String HW = "1.1.x"; + private static final String SW1 = "3.8.1"; + private static final String SW2 = "3.9.5"; + private static final String SN = "43311-12345"; + private static final ChassisId CID = new ChassisId(); + + private static final PortNumber P1 = PortNumber.portNumber(1); + private static final PortNumber P2 = PortNumber.portNumber(2); + private static final PortNumber P3 = PortNumber.portNumber(3); + + private static final SparseAnnotations A1 = DefaultAnnotations.builder() + .set("A1", "a1") + .set("B1", "b1") + .build(); + private static final SparseAnnotations A1_2 = DefaultAnnotations.builder() + .remove("A1") + .set("B3", "b3") + .build(); + private static final SparseAnnotations A2 = DefaultAnnotations.builder() + .set("A2", "a2") + .set("B2", "b2") + .build(); + private static final SparseAnnotations A2_2 = DefaultAnnotations.builder() + .remove("A2") + .set("B4", "b4") + .build(); + + private SimpleDeviceStore simpleDeviceStore; + private DeviceStore deviceStore; + + + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + + @Before + public void setUp() throws Exception { + simpleDeviceStore = new SimpleDeviceStore(); + simpleDeviceStore.activate(); + deviceStore = simpleDeviceStore; + } + + @After + public void tearDown() throws Exception { + simpleDeviceStore.deactivate(); + } + + private void putDevice(DeviceId deviceId, String swVersion, + SparseAnnotations... annotations) { + DeviceDescription description = + new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR, + HW, swVersion, SN, CID, annotations); + deviceStore.createOrUpdateDevice(PID, deviceId, description); + } + + private void putDeviceAncillary(DeviceId deviceId, String swVersion, + SparseAnnotations... annotations) { + DeviceDescription description = + new DefaultDeviceDescription(deviceId.uri(), SWITCH, MFR, + HW, swVersion, SN, CID, annotations); + deviceStore.createOrUpdateDevice(PIDA, deviceId, description); + } + + private static void assertDevice(DeviceId id, String swVersion, Device device) { + assertNotNull(device); + assertEquals(id, device.id()); + assertEquals(MFR, device.manufacturer()); + assertEquals(HW, device.hwVersion()); + assertEquals(swVersion, device.swVersion()); + assertEquals(SN, device.serialNumber()); + } + + @Test + public final void testGetDeviceCount() { + assertEquals("initialy empty", 0, deviceStore.getDeviceCount()); + + putDevice(DID1, SW1); + putDevice(DID2, SW2); + putDevice(DID1, SW1); + + assertEquals("expect 2 uniq devices", 2, deviceStore.getDeviceCount()); + } + + @Test + public final void testGetDevices() { + assertEquals("initialy empty", 0, Iterables.size(deviceStore.getDevices())); + + putDevice(DID1, SW1); + putDevice(DID2, SW2); + putDevice(DID1, SW1); + + assertEquals("expect 2 uniq devices", + 2, Iterables.size(deviceStore.getDevices())); + + Map devices = new HashMap<>(); + for (Device device : deviceStore.getDevices()) { + devices.put(device.id(), device); + } + + assertDevice(DID1, SW1, devices.get(DID1)); + assertDevice(DID2, SW2, devices.get(DID2)); + + // add case for new node? + } + + @Test + public final void testGetDevice() { + + putDevice(DID1, SW1); + + assertDevice(DID1, SW1, deviceStore.getDevice(DID1)); + assertNull("DID2 shouldn't be there", deviceStore.getDevice(DID2)); + } + + @Test + public final void testCreateOrUpdateDevice() { + DeviceDescription description = + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, + HW, SW1, SN, CID); + DeviceEvent event = deviceStore.createOrUpdateDevice(PID, DID1, description); + assertEquals(DEVICE_ADDED, event.type()); + assertDevice(DID1, SW1, event.subject()); + + DeviceDescription description2 = + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, + HW, SW2, SN, CID); + DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); + assertEquals(DEVICE_UPDATED, event2.type()); + assertDevice(DID1, SW2, event2.subject()); + + assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2)); + } + + @Test + public final void testCreateOrUpdateDeviceAncillary() { + DeviceDescription description = + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, + HW, SW1, SN, CID, A2); + DeviceEvent event = deviceStore.createOrUpdateDevice(PIDA, DID1, description); + assertEquals(DEVICE_ADDED, event.type()); + assertDevice(DID1, SW1, event.subject()); + assertEquals(PIDA, event.subject().providerId()); + assertAnnotationsEquals(event.subject().annotations(), A2); + assertFalse("Ancillary will not bring device up", deviceStore.isAvailable(DID1)); + + DeviceDescription description2 = + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, + HW, SW2, SN, CID, A1); + DeviceEvent event2 = deviceStore.createOrUpdateDevice(PID, DID1, description2); + assertEquals(DEVICE_UPDATED, event2.type()); + assertDevice(DID1, SW2, event2.subject()); + assertEquals(PID, event2.subject().providerId()); + assertAnnotationsEquals(event2.subject().annotations(), A1, A2); + assertTrue(deviceStore.isAvailable(DID1)); + + assertNull("No change expected", deviceStore.createOrUpdateDevice(PID, DID1, description2)); + + // For now, Ancillary is ignored once primary appears + assertNull("No change expected", deviceStore.createOrUpdateDevice(PIDA, DID1, description)); + + // But, Ancillary annotations will be in effect + DeviceDescription description3 = + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, + HW, SW1, SN, CID, A2_2); + DeviceEvent event3 = deviceStore.createOrUpdateDevice(PIDA, DID1, description3); + assertEquals(DEVICE_UPDATED, event3.type()); + // basic information will be the one from Primary + assertDevice(DID1, SW2, event3.subject()); + assertEquals(PID, event3.subject().providerId()); + // but annotation from Ancillary will be merged + assertAnnotationsEquals(event3.subject().annotations(), A1, A2, A2_2); + assertTrue(deviceStore.isAvailable(DID1)); + } + + + @Test + public final void testMarkOffline() { + + putDevice(DID1, SW1); + assertTrue(deviceStore.isAvailable(DID1)); + + DeviceEvent event = deviceStore.markOffline(DID1); + assertEquals(DEVICE_AVAILABILITY_CHANGED, event.type()); + assertDevice(DID1, SW1, event.subject()); + assertFalse(deviceStore.isAvailable(DID1)); + + DeviceEvent event2 = deviceStore.markOffline(DID1); + assertNull("No change, no event", event2); +} + + @Test + public final void testUpdatePorts() { + putDevice(DID1, SW1); + List pds = Arrays.asList( + new DefaultPortDescription(P1, true), + new DefaultPortDescription(P2, true) + ); + + List events = deviceStore.updatePorts(PID, DID1, pds); + + Set expectedPorts = Sets.newHashSet(P1, P2); + for (DeviceEvent event : events) { + assertEquals(PORT_ADDED, event.type()); + assertDevice(DID1, SW1, event.subject()); + assertTrue("PortNumber is one of expected", + expectedPorts.remove(event.port().number())); + assertTrue("Port is enabled", event.port().isEnabled()); + } + assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty()); + + + List pds2 = Arrays.asList( + new DefaultPortDescription(P1, false), + new DefaultPortDescription(P2, true), + new DefaultPortDescription(P3, true) + ); + + events = deviceStore.updatePorts(PID, DID1, pds2); + assertFalse("event should be triggered", events.isEmpty()); + for (DeviceEvent event : events) { + PortNumber num = event.port().number(); + if (P1.equals(num)) { + assertEquals(PORT_UPDATED, event.type()); + assertDevice(DID1, SW1, event.subject()); + assertFalse("Port is disabled", event.port().isEnabled()); + } else if (P2.equals(num)) { + fail("P2 event not expected."); + } else if (P3.equals(num)) { + assertEquals(PORT_ADDED, event.type()); + assertDevice(DID1, SW1, event.subject()); + assertTrue("Port is enabled", event.port().isEnabled()); + } else { + fail("Unknown port number encountered: " + num); + } + } + + List pds3 = Arrays.asList( + new DefaultPortDescription(P1, false), + new DefaultPortDescription(P2, true) + ); + events = deviceStore.updatePorts(PID, DID1, pds3); + assertFalse("event should be triggered", events.isEmpty()); + for (DeviceEvent event : events) { + PortNumber num = event.port().number(); + if (P1.equals(num)) { + fail("P1 event not expected."); + } else if (P2.equals(num)) { + fail("P2 event not expected."); + } else if (P3.equals(num)) { + assertEquals(PORT_REMOVED, event.type()); + assertDevice(DID1, SW1, event.subject()); + assertTrue("Port was enabled", event.port().isEnabled()); + } else { + fail("Unknown port number encountered: " + num); + } + } + + } + + @Test + public final void testUpdatePortStatus() { + putDevice(DID1, SW1); + List pds = Arrays.asList( + new DefaultPortDescription(P1, true) + ); + deviceStore.updatePorts(PID, DID1, pds); + + DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, + new DefaultPortDescription(P1, false)); + assertEquals(PORT_UPDATED, event.type()); + assertDevice(DID1, SW1, event.subject()); + assertEquals(P1, event.port().number()); + assertFalse("Port is disabled", event.port().isEnabled()); + + } + + @Test + public final void testUpdatePortStatusAncillary() { + putDeviceAncillary(DID1, SW1); + putDevice(DID1, SW1); + List pds = Arrays.asList( + new DefaultPortDescription(P1, true, A1) + ); + deviceStore.updatePorts(PID, DID1, pds); + + DeviceEvent event = deviceStore.updatePortStatus(PID, DID1, + new DefaultPortDescription(P1, false, A1_2)); + assertEquals(PORT_UPDATED, event.type()); + assertDevice(DID1, SW1, event.subject()); + assertEquals(P1, event.port().number()); + assertAnnotationsEquals(event.port().annotations(), A1, A1_2); + assertFalse("Port is disabled", event.port().isEnabled()); + + DeviceEvent event2 = deviceStore.updatePortStatus(PIDA, DID1, + new DefaultPortDescription(P1, true)); + assertNull("Ancillary is ignored if primary exists", event2); + + // but, Ancillary annotation update will be notified + DeviceEvent event3 = deviceStore.updatePortStatus(PIDA, DID1, + new DefaultPortDescription(P1, true, A2)); + assertEquals(PORT_UPDATED, event3.type()); + assertDevice(DID1, SW1, event3.subject()); + assertEquals(P1, event3.port().number()); + assertAnnotationsEquals(event3.port().annotations(), A1, A1_2, A2); + assertFalse("Port is disabled", event3.port().isEnabled()); + + // port only reported from Ancillary will be notified as down + DeviceEvent event4 = deviceStore.updatePortStatus(PIDA, DID1, + new DefaultPortDescription(P2, true)); + assertEquals(PORT_ADDED, event4.type()); + assertDevice(DID1, SW1, event4.subject()); + assertEquals(P2, event4.port().number()); + assertAnnotationsEquals(event4.port().annotations()); + assertFalse("Port is disabled if not given from primary provider", + event4.port().isEnabled()); + } + + @Test + public final void testGetPorts() { + putDevice(DID1, SW1); + putDevice(DID2, SW1); + List pds = Arrays.asList( + new DefaultPortDescription(P1, true), + new DefaultPortDescription(P2, true) + ); + deviceStore.updatePorts(PID, DID1, pds); + + Set expectedPorts = Sets.newHashSet(P1, P2); + List ports = deviceStore.getPorts(DID1); + for (Port port : ports) { + assertTrue("Port is enabled", port.isEnabled()); + assertTrue("PortNumber is one of expected", + expectedPorts.remove(port.number())); + } + assertTrue("Event for all expectedport appeared", expectedPorts.isEmpty()); + + + assertTrue("DID2 has no ports", deviceStore.getPorts(DID2).isEmpty()); + } + + @Test + public final void testGetPort() { + putDevice(DID1, SW1); + putDevice(DID2, SW1); + List pds = Arrays.asList( + new DefaultPortDescription(P1, true), + new DefaultPortDescription(P2, false) + ); + deviceStore.updatePorts(PID, DID1, pds); + + Port port1 = deviceStore.getPort(DID1, P1); + assertEquals(P1, port1.number()); + assertTrue("Port is enabled", port1.isEnabled()); + + Port port2 = deviceStore.getPort(DID1, P2); + assertEquals(P2, port2.number()); + assertFalse("Port is disabled", port2.isEnabled()); + + Port port3 = deviceStore.getPort(DID1, P3); + assertNull("P3 not expected", port3); + } + + @Test + public final void testRemoveDevice() { + putDevice(DID1, SW1, A1); + List pds = Arrays.asList( + new DefaultPortDescription(P1, true, A2) + ); + deviceStore.updatePorts(PID, DID1, pds); + putDevice(DID2, SW1); + + assertEquals(2, deviceStore.getDeviceCount()); + assertEquals(1, deviceStore.getPorts(DID1).size()); + assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations(), A1); + assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations(), A2); + + DeviceEvent event = deviceStore.removeDevice(DID1); + assertEquals(DEVICE_REMOVED, event.type()); + assertDevice(DID1, SW1, event.subject()); + + assertEquals(1, deviceStore.getDeviceCount()); + assertEquals(0, deviceStore.getPorts(DID1).size()); + + // putBack Device, Port w/o annotation + putDevice(DID1, SW1); + List pds2 = Arrays.asList( + new DefaultPortDescription(P1, true) + ); + deviceStore.updatePorts(PID, DID1, pds2); + + // annotations should not survive + assertEquals(2, deviceStore.getDeviceCount()); + assertEquals(1, deviceStore.getPorts(DID1).size()); + assertAnnotationsEquals(deviceStore.getDevice(DID1).annotations()); + assertAnnotationsEquals(deviceStore.getPort(DID1, P1).annotations()); + } + + // If Delegates should be called only on remote events, + // then Simple* should never call them, thus not test required. + // TODO add test for Port events when we have them + @Ignore("Ignore until Delegate spec. is clear.") + @Test + public final void testEvents() throws InterruptedException { + final CountDownLatch addLatch = new CountDownLatch(1); + DeviceStoreDelegate checkAdd = new DeviceStoreDelegate() { + @Override + public void notify(DeviceEvent event) { + assertEquals(DEVICE_ADDED, event.type()); + assertDevice(DID1, SW1, event.subject()); + addLatch.countDown(); + } + }; + final CountDownLatch updateLatch = new CountDownLatch(1); + DeviceStoreDelegate checkUpdate = new DeviceStoreDelegate() { + @Override + public void notify(DeviceEvent event) { + assertEquals(DEVICE_UPDATED, event.type()); + assertDevice(DID1, SW2, event.subject()); + updateLatch.countDown(); + } + }; + final CountDownLatch removeLatch = new CountDownLatch(1); + DeviceStoreDelegate checkRemove = new DeviceStoreDelegate() { + @Override + public void notify(DeviceEvent event) { + assertEquals(DEVICE_REMOVED, event.type()); + assertDevice(DID1, SW2, event.subject()); + removeLatch.countDown(); + } + }; + + DeviceDescription description = + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, + HW, SW1, SN, CID); + deviceStore.setDelegate(checkAdd); + deviceStore.createOrUpdateDevice(PID, DID1, description); + assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS)); + + + DeviceDescription description2 = + new DefaultDeviceDescription(DID1.uri(), SWITCH, MFR, + HW, SW2, SN, CID); + deviceStore.unsetDelegate(checkAdd); + deviceStore.setDelegate(checkUpdate); + deviceStore.createOrUpdateDevice(PID, DID1, description2); + assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS)); + + deviceStore.unsetDelegate(checkUpdate); + deviceStore.setDelegate(checkRemove); + deviceStore.removeDevice(DID1); + assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS)); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java new file mode 100644 index 00000000..3b8f1d35 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleFlowRuleStore.java @@ -0,0 +1,327 @@ +/* + * Copyright 2014-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.trivial; + +import com.google.common.base.Function; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.RemovalListener; +import com.google.common.cache.RemovalNotification; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.SettableFuture; +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.Service; +import org.onlab.util.NewConcurrentHashMap; +import org.onosproject.net.DeviceId; +import org.onosproject.net.flow.CompletedBatchOperation; +import org.onosproject.net.flow.DefaultFlowEntry; +import org.onosproject.net.flow.FlowEntry; +import org.onosproject.net.flow.FlowEntry.FlowEntryState; +import org.onosproject.net.flow.FlowId; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.FlowRuleBatchEntry; +import org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation; +import org.onosproject.net.flow.FlowRuleBatchEvent; +import org.onosproject.net.flow.FlowRuleBatchOperation; +import org.onosproject.net.flow.FlowRuleBatchRequest; +import org.onosproject.net.flow.FlowRuleEvent; +import org.onosproject.net.flow.FlowRuleEvent.Type; +import org.onosproject.net.flow.FlowRuleStore; +import org.onosproject.net.flow.FlowRuleStoreDelegate; +import org.onosproject.net.flow.StoredFlowEntry; +import org.onosproject.store.AbstractStore; +import org.slf4j.Logger; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; +import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVED; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Manages inventory of flow rules using trivial in-memory implementation. + */ +@Component(immediate = true) +@Service +public class SimpleFlowRuleStore + extends AbstractStore + implements FlowRuleStore { + + private final Logger log = getLogger(getClass()); + + + // inner Map is Device flow table + // inner Map value (FlowId synonym list) must be synchronized before modifying + private final ConcurrentMap>> + flowEntries = new ConcurrentHashMap<>(); + + private final AtomicInteger localBatchIdGen = new AtomicInteger(); + + // TODO: make this configurable + private int pendingFutureTimeoutMinutes = 5; + + private Cache> pendingFutures = + CacheBuilder.newBuilder() + .expireAfterWrite(pendingFutureTimeoutMinutes, TimeUnit.MINUTES) + .removalListener(new TimeoutFuture()) + .build(); + + @Activate + public void activate() { + log.info("Started"); + } + + @Deactivate + public void deactivate() { + flowEntries.clear(); + log.info("Stopped"); + } + + + @Override + public int getFlowRuleCount() { + int sum = 0; + for (ConcurrentMap> ft : flowEntries.values()) { + for (List fes : ft.values()) { + sum += fes.size(); + } + } + return sum; + } + + private static NewConcurrentHashMap> lazyEmptyFlowTable() { + return NewConcurrentHashMap.>ifNeeded(); + } + + /** + * Returns the flow table for specified device. + * + * @param deviceId identifier of the device + * @return Map representing Flow Table of given device. + */ + private ConcurrentMap> getFlowTable(DeviceId deviceId) { + return createIfAbsentUnchecked(flowEntries, + deviceId, lazyEmptyFlowTable()); + } + + private List getFlowEntries(DeviceId deviceId, FlowId flowId) { + final ConcurrentMap> flowTable = getFlowTable(deviceId); + List r = flowTable.get(flowId); + if (r == null) { + final List concurrentlyAdded; + r = new CopyOnWriteArrayList<>(); + concurrentlyAdded = flowTable.putIfAbsent(flowId, r); + if (concurrentlyAdded != null) { + return concurrentlyAdded; + } + } + return r; + } + + private FlowEntry getFlowEntryInternal(DeviceId deviceId, FlowRule rule) { + List fes = getFlowEntries(deviceId, rule.id()); + for (StoredFlowEntry fe : fes) { + if (fe.equals(rule)) { + return fe; + } + } + return null; + } + + @Override + public FlowEntry getFlowEntry(FlowRule rule) { + return getFlowEntryInternal(rule.deviceId(), rule); + } + + @Override + public Iterable getFlowEntries(DeviceId deviceId) { + // flatten and make iterator unmodifiable + return FluentIterable.from(getFlowTable(deviceId).values()) + .transformAndConcat( + new Function, Iterable>() { + + @Override + public Iterable apply( + List input) { + return Collections.unmodifiableList(input); + } + }); + } + + @Override + public void storeFlowRule(FlowRule rule) { + storeFlowRuleInternal(rule); + } + + private void storeFlowRuleInternal(FlowRule rule) { + StoredFlowEntry f = new DefaultFlowEntry(rule); + final DeviceId did = f.deviceId(); + final FlowId fid = f.id(); + List existing = getFlowEntries(did, fid); + synchronized (existing) { + for (StoredFlowEntry fe : existing) { + if (fe.equals(rule)) { + // was already there? ignore + return; + } + } + // new flow rule added + existing.add(f); + } + } + + @Override + public void deleteFlowRule(FlowRule rule) { + + List entries = getFlowEntries(rule.deviceId(), rule.id()); + + synchronized (entries) { + for (StoredFlowEntry entry : entries) { + if (entry.equals(rule)) { + synchronized (entry) { + entry.setState(FlowEntryState.PENDING_REMOVE); + } + } + } + } + + + //log.warn("Cannot find rule {}", rule); + } + + @Override + public FlowRuleEvent addOrUpdateFlowRule(FlowEntry rule) { + // check if this new rule is an update to an existing entry + List entries = getFlowEntries(rule.deviceId(), rule.id()); + synchronized (entries) { + for (StoredFlowEntry stored : entries) { + if (stored.equals(rule)) { + synchronized (stored) { + stored.setBytes(rule.bytes()); + stored.setLife(rule.life()); + stored.setPackets(rule.packets()); + if (stored.state() == FlowEntryState.PENDING_ADD) { + stored.setState(FlowEntryState.ADDED); + // TODO: Do we need to change `rule` state? + return new FlowRuleEvent(Type.RULE_ADDED, rule); + } + return new FlowRuleEvent(Type.RULE_UPDATED, rule); + } + } + } + } + + // should not reach here + // storeFlowRule was expected to be called + log.error("FlowRule was not found in store {} to update", rule); + + //flowEntries.put(did, rule); + return null; + } + + @Override + public FlowRuleEvent removeFlowRule(FlowEntry rule) { + // This is where one could mark a rule as removed and still keep it in the store. + final DeviceId did = rule.deviceId(); + + List entries = getFlowEntries(did, rule.id()); + synchronized (entries) { + if (entries.remove(rule)) { + return new FlowRuleEvent(RULE_REMOVED, rule); + } + } + return null; + } + + @Override + public void storeBatch( + FlowRuleBatchOperation operation) { + List toAdd = new ArrayList<>(); + List toRemove = new ArrayList<>(); + + for (FlowRuleBatchEntry entry : operation.getOperations()) { + final FlowRule flowRule = entry.target(); + if (entry.operator().equals(FlowRuleOperation.ADD)) { + if (!getFlowEntries(flowRule.deviceId(), flowRule.id()).contains(flowRule)) { + storeFlowRule(flowRule); + toAdd.add(entry); + } + } else if (entry.operator().equals(FlowRuleOperation.REMOVE)) { + if (getFlowEntries(flowRule.deviceId(), flowRule.id()).contains(flowRule)) { + deleteFlowRule(flowRule); + toRemove.add(entry); + } + } else { + throw new UnsupportedOperationException("Unsupported operation type"); + } + } + + if (toAdd.isEmpty() && toRemove.isEmpty()) { + notifyDelegate(FlowRuleBatchEvent.completed( + new FlowRuleBatchRequest(operation.id(), Collections.emptySet()), + new CompletedBatchOperation(true, Collections.emptySet(), + operation.deviceId()))); + return; + } + + SettableFuture r = SettableFuture.create(); + final int batchId = localBatchIdGen.incrementAndGet(); + + pendingFutures.put(batchId, r); + + toAdd.addAll(toRemove); + notifyDelegate(FlowRuleBatchEvent.requested( + new FlowRuleBatchRequest(batchId, Sets.newHashSet(toAdd)), operation.deviceId())); + + } + + @Override + public void batchOperationComplete(FlowRuleBatchEvent event) { + final Long batchId = event.subject().batchId(); + SettableFuture future + = pendingFutures.getIfPresent(batchId); + if (future != null) { + future.set(event.result()); + pendingFutures.invalidate(batchId); + } + notifyDelegate(event); + } + + private static final class TimeoutFuture + implements RemovalListener> { + @Override + public void onRemoval(RemovalNotification> notification) { + // wrapping in ExecutionException to support Future.get + if (notification.wasEvicted()) { + notification.getValue() + .setException(new ExecutionException("Timed out", + new TimeoutException())); + } + } + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleGroupStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleGroupStore.java new file mode 100644 index 00000000..71de3e13 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleGroupStore.java @@ -0,0 +1,717 @@ +/* + * 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.trivial; + +import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; +import static org.slf4j.LoggerFactory.getLogger; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; + +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.Service; +import org.onlab.util.NewConcurrentHashMap; +import org.onosproject.core.DefaultGroupId; +import org.onosproject.core.GroupId; +import org.onosproject.net.DeviceId; +import org.onosproject.net.group.DefaultGroup; +import org.onosproject.net.group.DefaultGroupDescription; +import org.onosproject.net.group.Group; +import org.onosproject.net.group.Group.GroupState; +import org.onosproject.net.group.GroupBucket; +import org.onosproject.net.group.GroupBuckets; +import org.onosproject.net.group.GroupDescription; +import org.onosproject.net.group.GroupEvent; +import org.onosproject.net.group.GroupEvent.Type; +import org.onosproject.net.group.GroupKey; +import org.onosproject.net.group.GroupOperation; +import org.onosproject.net.group.GroupStore; +import org.onosproject.net.group.GroupStoreDelegate; +import org.onosproject.net.group.StoredGroupBucketEntry; +import org.onosproject.net.group.StoredGroupEntry; +import org.onosproject.store.AbstractStore; +import org.slf4j.Logger; + +import com.google.common.base.Function; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.Sets; + +/** + * Manages inventory of group entries using trivial in-memory implementation. + */ +@Component(immediate = true) +@Service +public class SimpleGroupStore + extends AbstractStore + implements GroupStore { + + private final Logger log = getLogger(getClass()); + + private final int dummyId = 0xffffffff; + private final GroupId dummyGroupId = new DefaultGroupId(dummyId); + + // inner Map is per device group table + private final ConcurrentMap> + groupEntriesByKey = new ConcurrentHashMap<>(); + private final ConcurrentMap> + groupEntriesById = new ConcurrentHashMap<>(); + private final ConcurrentMap> + pendingGroupEntriesByKey = new ConcurrentHashMap<>(); + private final ConcurrentMap> + extraneousGroupEntriesById = new ConcurrentHashMap<>(); + + private final HashMap deviceAuditStatus = + new HashMap(); + + private final AtomicInteger groupIdGen = new AtomicInteger(); + + @Activate + public void activate() { + log.info("Started"); + } + + @Deactivate + public void deactivate() { + groupEntriesByKey.clear(); + groupEntriesById.clear(); + log.info("Stopped"); + } + + private static NewConcurrentHashMap + lazyEmptyGroupKeyTable() { + return NewConcurrentHashMap.ifNeeded(); + } + + private static NewConcurrentHashMap + lazyEmptyGroupIdTable() { + return NewConcurrentHashMap.ifNeeded(); + } + + private static NewConcurrentHashMap + lazyEmptyPendingGroupKeyTable() { + return NewConcurrentHashMap.ifNeeded(); + } + + private static NewConcurrentHashMap + lazyEmptyExtraneousGroupIdTable() { + return NewConcurrentHashMap.ifNeeded(); + } + + /** + * Returns the group key table for specified device. + * + * @param deviceId identifier of the device + * @return Map representing group key table of given device. + */ + private ConcurrentMap getGroupKeyTable(DeviceId deviceId) { + return createIfAbsentUnchecked(groupEntriesByKey, + deviceId, lazyEmptyGroupKeyTable()); + } + + /** + * Returns the group id table for specified device. + * + * @param deviceId identifier of the device + * @return Map representing group key table of given device. + */ + private ConcurrentMap getGroupIdTable(DeviceId deviceId) { + return createIfAbsentUnchecked(groupEntriesById, + deviceId, lazyEmptyGroupIdTable()); + } + + /** + * Returns the pending group key table for specified device. + * + * @param deviceId identifier of the device + * @return Map representing group key table of given device. + */ + private ConcurrentMap + getPendingGroupKeyTable(DeviceId deviceId) { + return createIfAbsentUnchecked(pendingGroupEntriesByKey, + deviceId, lazyEmptyPendingGroupKeyTable()); + } + + /** + * Returns the extraneous group id table for specified device. + * + * @param deviceId identifier of the device + * @return Map representing group key table of given device. + */ + private ConcurrentMap + getExtraneousGroupIdTable(DeviceId deviceId) { + return createIfAbsentUnchecked(extraneousGroupEntriesById, + deviceId, + lazyEmptyExtraneousGroupIdTable()); + } + + /** + * Returns the number of groups for the specified device in the store. + * + * @return number of groups for the specified device + */ + @Override + public int getGroupCount(DeviceId deviceId) { + return (groupEntriesByKey.get(deviceId) != null) ? + groupEntriesByKey.get(deviceId).size() : 0; + } + + /** + * Returns the groups associated with a device. + * + * @param deviceId the device ID + * + * @return the group entries + */ + @Override + public Iterable getGroups(DeviceId deviceId) { + // flatten and make iterator unmodifiable + return FluentIterable.from(getGroupKeyTable(deviceId).values()) + .transform( + new Function() { + + @Override + public Group apply( + StoredGroupEntry input) { + return input; + } + }); + } + + /** + * Returns the stored group entry. + * + * @param deviceId the device ID + * @param appCookie the group key + * + * @return a group associated with the key + */ + @Override + public Group getGroup(DeviceId deviceId, GroupKey appCookie) { + return (groupEntriesByKey.get(deviceId) != null) ? + groupEntriesByKey.get(deviceId).get(appCookie) : + null; + } + + @Override + public Group getGroup(DeviceId deviceId, GroupId groupId) { + return (groupEntriesById.get(deviceId) != null) ? + groupEntriesById.get(deviceId).get(groupId) : + null; + } + + private int getFreeGroupIdValue(DeviceId deviceId) { + int freeId = groupIdGen.incrementAndGet(); + + while (true) { + Group existing = ( + groupEntriesById.get(deviceId) != null) ? + groupEntriesById.get(deviceId).get(new DefaultGroupId(freeId)) : + null; + if (existing == null) { + existing = ( + extraneousGroupEntriesById.get(deviceId) != null) ? + extraneousGroupEntriesById.get(deviceId). + get(new DefaultGroupId(freeId)) : + null; + } + if (existing != null) { + freeId = groupIdGen.incrementAndGet(); + } else { + break; + } + } + return freeId; + } + + /** + * Stores a new group entry using the information from group description. + * + * @param groupDesc group description to be used to create group entry + */ + @Override + public void storeGroupDescription(GroupDescription groupDesc) { + // Check if a group is existing with the same key + if (getGroup(groupDesc.deviceId(), groupDesc.appCookie()) != null) { + return; + } + + if (deviceAuditStatus.get(groupDesc.deviceId()) == null) { + // Device group audit has not completed yet + // Add this group description to pending group key table + // Create a group entry object with Dummy Group ID + StoredGroupEntry group = new DefaultGroup(dummyGroupId, groupDesc); + group.setState(GroupState.WAITING_AUDIT_COMPLETE); + ConcurrentMap pendingKeyTable = + getPendingGroupKeyTable(groupDesc.deviceId()); + pendingKeyTable.put(groupDesc.appCookie(), group); + return; + } + + storeGroupDescriptionInternal(groupDesc); + } + + private void storeGroupDescriptionInternal(GroupDescription groupDesc) { + // Check if a group is existing with the same key + if (getGroup(groupDesc.deviceId(), groupDesc.appCookie()) != null) { + return; + } + + GroupId id = null; + if (groupDesc.givenGroupId() == null) { + // Get a new group identifier + id = new DefaultGroupId(getFreeGroupIdValue(groupDesc.deviceId())); + } else { + id = new DefaultGroupId(groupDesc.givenGroupId()); + } + // Create a group entry object + StoredGroupEntry group = new DefaultGroup(id, groupDesc); + // Insert the newly created group entry into concurrent key and id maps + ConcurrentMap keyTable = + getGroupKeyTable(groupDesc.deviceId()); + keyTable.put(groupDesc.appCookie(), group); + ConcurrentMap idTable = + getGroupIdTable(groupDesc.deviceId()); + idTable.put(id, group); + notifyDelegate(new GroupEvent(GroupEvent.Type.GROUP_ADD_REQUESTED, + group)); + } + + /** + * Updates the existing group entry with the information + * from group description. + * + * @param deviceId the device ID + * @param oldAppCookie the current group key + * @param type update type + * @param newBuckets group buckets for updates + * @param newAppCookie optional new group key + */ + @Override + public void updateGroupDescription(DeviceId deviceId, + GroupKey oldAppCookie, + UpdateType type, + GroupBuckets newBuckets, + GroupKey newAppCookie) { + // Check if a group is existing with the provided key + Group oldGroup = getGroup(deviceId, oldAppCookie); + if (oldGroup == null) { + return; + } + + List newBucketList = getUpdatedBucketList(oldGroup, + type, + newBuckets); + if (newBucketList != null) { + // Create a new group object from the old group + GroupBuckets updatedBuckets = new GroupBuckets(newBucketList); + GroupKey newCookie = (newAppCookie != null) ? newAppCookie : oldAppCookie; + GroupDescription updatedGroupDesc = new DefaultGroupDescription( + oldGroup.deviceId(), + oldGroup.type(), + updatedBuckets, + newCookie, + oldGroup.givenGroupId(), + oldGroup.appId()); + StoredGroupEntry newGroup = new DefaultGroup(oldGroup.id(), + updatedGroupDesc); + newGroup.setState(GroupState.PENDING_UPDATE); + newGroup.setLife(oldGroup.life()); + newGroup.setPackets(oldGroup.packets()); + newGroup.setBytes(oldGroup.bytes()); + // Remove the old entry from maps and add new entry using new key + ConcurrentMap keyTable = + getGroupKeyTable(oldGroup.deviceId()); + ConcurrentMap idTable = + getGroupIdTable(oldGroup.deviceId()); + keyTable.remove(oldGroup.appCookie()); + idTable.remove(oldGroup.id()); + keyTable.put(newGroup.appCookie(), newGroup); + idTable.put(newGroup.id(), newGroup); + notifyDelegate(new GroupEvent(Type.GROUP_UPDATE_REQUESTED, newGroup)); + } + } + + private List getUpdatedBucketList(Group oldGroup, + UpdateType type, + GroupBuckets buckets) { + GroupBuckets oldBuckets = oldGroup.buckets(); + List newBucketList = new ArrayList( + oldBuckets.buckets()); + boolean groupDescUpdated = false; + + if (type == UpdateType.ADD) { + // Check if the any of the new buckets are part of + // the old bucket list + for (GroupBucket addBucket:buckets.buckets()) { + if (!newBucketList.contains(addBucket)) { + newBucketList.add(addBucket); + groupDescUpdated = true; + } + } + } else if (type == UpdateType.REMOVE) { + // Check if the to be removed buckets are part of the + // old bucket list + for (GroupBucket removeBucket:buckets.buckets()) { + if (newBucketList.contains(removeBucket)) { + newBucketList.remove(removeBucket); + groupDescUpdated = true; + } + } + } + + if (groupDescUpdated) { + return newBucketList; + } else { + return null; + } + } + + /** + * Triggers deleting the existing group entry. + * + * @param deviceId the device ID + * @param appCookie the group key + */ + @Override + public void deleteGroupDescription(DeviceId deviceId, + GroupKey appCookie) { + // Check if a group is existing with the provided key + StoredGroupEntry existing = (groupEntriesByKey.get(deviceId) != null) ? + groupEntriesByKey.get(deviceId).get(appCookie) : + null; + if (existing == null) { + return; + } + + synchronized (existing) { + existing.setState(GroupState.PENDING_DELETE); + } + notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_REQUESTED, existing)); + } + + /** + * Stores a new group entry, or updates an existing entry. + * + * @param group group entry + */ + @Override + public void addOrUpdateGroupEntry(Group group) { + // check if this new entry is an update to an existing entry + StoredGroupEntry existing = (groupEntriesById.get( + group.deviceId()) != null) ? + groupEntriesById.get(group.deviceId()).get(group.id()) : + null; + GroupEvent event = null; + + if (existing != null) { + synchronized (existing) { + for (GroupBucket bucket:group.buckets().buckets()) { + Optional matchingBucket = + existing.buckets().buckets() + .stream() + .filter((existingBucket)->(existingBucket.equals(bucket))) + .findFirst(); + if (matchingBucket.isPresent()) { + ((StoredGroupBucketEntry) matchingBucket. + get()).setPackets(bucket.packets()); + ((StoredGroupBucketEntry) matchingBucket. + get()).setBytes(bucket.bytes()); + } else { + log.warn("addOrUpdateGroupEntry: No matching " + + "buckets to update stats"); + } + } + existing.setLife(group.life()); + existing.setPackets(group.packets()); + existing.setBytes(group.bytes()); + if (existing.state() == GroupState.PENDING_ADD) { + existing.setState(GroupState.ADDED); + event = new GroupEvent(Type.GROUP_ADDED, existing); + } else { + if (existing.state() == GroupState.PENDING_UPDATE) { + existing.setState(GroupState.ADDED); + } + event = new GroupEvent(Type.GROUP_UPDATED, existing); + } + } + } + + if (event != null) { + notifyDelegate(event); + } + } + + /** + * Removes the group entry from store. + * + * @param group group entry + */ + @Override + public void removeGroupEntry(Group group) { + StoredGroupEntry existing = (groupEntriesById.get( + group.deviceId()) != null) ? + groupEntriesById.get(group.deviceId()).get(group.id()) : + null; + + if (existing != null) { + ConcurrentMap keyTable = + getGroupKeyTable(existing.deviceId()); + ConcurrentMap idTable = + getGroupIdTable(existing.deviceId()); + idTable.remove(existing.id()); + keyTable.remove(existing.appCookie()); + notifyDelegate(new GroupEvent(Type.GROUP_REMOVED, existing)); + } + } + + @Override + public void deviceInitialAuditCompleted(DeviceId deviceId, + boolean completed) { + synchronized (deviceAuditStatus) { + if (completed) { + log.debug("deviceInitialAuditCompleted: AUDIT " + + "completed for device {}", deviceId); + deviceAuditStatus.put(deviceId, true); + // Execute all pending group requests + ConcurrentMap pendingGroupRequests = + getPendingGroupKeyTable(deviceId); + for (Group group:pendingGroupRequests.values()) { + GroupDescription tmp = new DefaultGroupDescription( + group.deviceId(), + group.type(), + group.buckets(), + group.appCookie(), + group.givenGroupId(), + group.appId()); + storeGroupDescriptionInternal(tmp); + } + getPendingGroupKeyTable(deviceId).clear(); + } else { + if (deviceAuditStatus.get(deviceId)) { + log.debug("deviceInitialAuditCompleted: Clearing AUDIT " + + "status for device {}", deviceId); + deviceAuditStatus.put(deviceId, false); + } + } + } + } + + @Override + public boolean deviceInitialAuditStatus(DeviceId deviceId) { + synchronized (deviceAuditStatus) { + return (deviceAuditStatus.get(deviceId) != null) + ? deviceAuditStatus.get(deviceId) : false; + } + } + + @Override + public void groupOperationFailed(DeviceId deviceId, GroupOperation operation) { + + StoredGroupEntry existing = (groupEntriesById.get( + deviceId) != null) ? + groupEntriesById.get(deviceId).get(operation.groupId()) : + null; + + if (existing == null) { + log.warn("No group entry with ID {} found ", operation.groupId()); + return; + } + + switch (operation.opType()) { + case ADD: + notifyDelegate(new GroupEvent(Type.GROUP_ADD_FAILED, existing)); + break; + case MODIFY: + notifyDelegate(new GroupEvent(Type.GROUP_UPDATE_FAILED, existing)); + break; + case DELETE: + notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_FAILED, existing)); + break; + default: + log.warn("Unknown group operation type {}", operation.opType()); + } + + ConcurrentMap keyTable = + getGroupKeyTable(existing.deviceId()); + ConcurrentMap idTable = + getGroupIdTable(existing.deviceId()); + idTable.remove(existing.id()); + keyTable.remove(existing.appCookie()); + } + + @Override + public void addOrUpdateExtraneousGroupEntry(Group group) { + ConcurrentMap extraneousIdTable = + getExtraneousGroupIdTable(group.deviceId()); + extraneousIdTable.put(group.id(), group); + // Check the reference counter + if (group.referenceCount() == 0) { + notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_REQUESTED, group)); + } + } + + @Override + public void removeExtraneousGroupEntry(Group group) { + ConcurrentMap extraneousIdTable = + getExtraneousGroupIdTable(group.deviceId()); + extraneousIdTable.remove(group.id()); + } + + @Override + public Iterable getExtraneousGroups(DeviceId deviceId) { + // flatten and make iterator unmodifiable + return FluentIterable.from( + getExtraneousGroupIdTable(deviceId).values()); + } + + @Override + public void pushGroupMetrics(DeviceId deviceId, + Collection groupEntries) { + boolean deviceInitialAuditStatus = + deviceInitialAuditStatus(deviceId); + Set southboundGroupEntries = + Sets.newHashSet(groupEntries); + Set storedGroupEntries = + Sets.newHashSet(getGroups(deviceId)); + Set extraneousStoredEntries = + Sets.newHashSet(getExtraneousGroups(deviceId)); + + log.trace("pushGroupMetrics: Displaying all ({}) " + + "southboundGroupEntries for device {}", + southboundGroupEntries.size(), + deviceId); + for (Iterator it = southboundGroupEntries.iterator(); it.hasNext();) { + Group group = it.next(); + log.trace("Group {} in device {}", group, deviceId); + } + + log.trace("Displaying all ({}) stored group entries for device {}", + storedGroupEntries.size(), + deviceId); + for (Iterator it1 = storedGroupEntries.iterator(); + it1.hasNext();) { + Group group = it1.next(); + log.trace("Stored Group {} for device {}", group, deviceId); + } + + for (Iterator it2 = southboundGroupEntries.iterator(); it2.hasNext();) { + Group group = it2.next(); + if (storedGroupEntries.remove(group)) { + // we both have the group, let's update some info then. + log.trace("Group AUDIT: group {} exists " + + "in both planes for device {}", + group.id(), deviceId); + groupAdded(group); + it2.remove(); + } + } + for (Group group : southboundGroupEntries) { + if (getGroup(group.deviceId(), group.id()) != null) { + // There is a group existing with the same id + // It is possible that group update is + // in progress while we got a stale info from switch + if (!storedGroupEntries.remove(getGroup( + group.deviceId(), group.id()))) { + log.warn("Group AUDIT: Inconsistent state:" + + "Group exists in ID based table while " + + "not present in key based table"); + } + } else { + // there are groups in the switch that aren't in the store + log.trace("Group AUDIT: extraneous group {} exists " + + "in data plane for device {}", + group.id(), deviceId); + extraneousStoredEntries.remove(group); + extraneousGroup(group); + } + } + for (Group group : storedGroupEntries) { + // there are groups in the store that aren't in the switch + log.trace("Group AUDIT: group {} missing " + + "in data plane for device {}", + group.id(), deviceId); + groupMissing(group); + } + for (Group group : extraneousStoredEntries) { + // there are groups in the extraneous store that + // aren't in the switch + log.trace("Group AUDIT: clearing extransoeus group {} " + + "from store for device {}", + group.id(), deviceId); + removeExtraneousGroupEntry(group); + } + + if (!deviceInitialAuditStatus) { + log.debug("Group AUDIT: Setting device {} initial " + + "AUDIT completed", deviceId); + deviceInitialAuditCompleted(deviceId, true); + } + } + + private void groupMissing(Group group) { + switch (group.state()) { + case PENDING_DELETE: + log.debug("Group {} delete confirmation from device {}", + group, group.deviceId()); + removeGroupEntry(group); + break; + case ADDED: + case PENDING_ADD: + case PENDING_UPDATE: + log.debug("Group {} is in store but not on device {}", + group, group.deviceId()); + StoredGroupEntry existing = (groupEntriesById.get( + group.deviceId()) != null) ? + groupEntriesById.get(group.deviceId()).get(group.id()) : + null; + log.trace("groupMissing: group " + + "entry {} in device {} moving " + + "from {} to PENDING_ADD", + existing.id(), + existing.deviceId(), + existing.state()); + existing.setState(Group.GroupState.PENDING_ADD); + notifyDelegate(new GroupEvent(GroupEvent.Type.GROUP_ADD_REQUESTED, + group)); + break; + default: + log.debug("Group {} has not been installed.", group); + break; + } + } + + private void extraneousGroup(Group group) { + log.debug("Group {} is on device {} but not in store.", + group, group.deviceId()); + addOrUpdateExtraneousGroupEntry(group); + } + + private void groupAdded(Group group) { + log.trace("Group {} Added or Updated in device {}", + group, group.deviceId()); + addOrUpdateGroupEntry(group); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleGroupStoreTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleGroupStoreTest.java new file mode 100644 index 00000000..dd6c8a58 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleGroupStoreTest.java @@ -0,0 +1,482 @@ +/* + * Copyright 2014-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.trivial; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.net.DeviceId.deviceId; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onlab.packet.MacAddress; +import org.onlab.packet.MplsLabel; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.DefaultApplicationId; +import org.onosproject.core.GroupId; +import org.onosproject.net.DeviceId; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.group.DefaultGroup; +import org.onosproject.net.group.DefaultGroupBucket; +import org.onosproject.net.group.DefaultGroupDescription; +import org.onosproject.net.group.DefaultGroupKey; +import org.onosproject.net.group.Group; +import org.onosproject.net.group.GroupBucket; +import org.onosproject.net.group.GroupBuckets; +import org.onosproject.net.group.GroupDescription; +import org.onosproject.net.group.GroupEvent; +import org.onosproject.net.group.GroupKey; +import org.onosproject.net.group.GroupOperation; +import org.onosproject.net.group.GroupStore.UpdateType; +import org.onosproject.net.group.GroupStoreDelegate; +import org.onosproject.net.group.StoredGroupBucketEntry; +import org.onosproject.net.group.StoredGroupEntry; + +import com.google.common.collect.Iterables; + +/** + * Test of the simple DeviceStore implementation. + */ +public class SimpleGroupStoreTest { + + private SimpleGroupStore simpleGroupStore; + private final ApplicationId appId = + new DefaultApplicationId(2, "org.groupstore.test"); + + public static final DeviceId D1 = deviceId("of:1"); + + @Before + public void setUp() throws Exception { + simpleGroupStore = new SimpleGroupStore(); + simpleGroupStore.activate(); + } + + @After + public void tearDown() throws Exception { + simpleGroupStore.deactivate(); + } + + private class InternalGroupStoreDelegate + implements GroupStoreDelegate { + private GroupId createdGroupId = null; + private GroupKey createdGroupKey; + private GroupBuckets createdBuckets; + private GroupEvent.Type expectedEvent; + + public InternalGroupStoreDelegate(GroupKey key, + GroupBuckets buckets, + GroupEvent.Type expectedEvent) { + this.createdBuckets = buckets; + this.createdGroupKey = key; + this.expectedEvent = expectedEvent; + } + @Override + public void notify(GroupEvent event) { + assertEquals(expectedEvent, event.type()); + assertEquals(Group.Type.SELECT, event.subject().type()); + assertEquals(D1, event.subject().deviceId()); + assertEquals(createdGroupKey, event.subject().appCookie()); + assertEquals(createdBuckets.buckets(), event.subject().buckets().buckets()); + if (expectedEvent == GroupEvent.Type.GROUP_ADD_REQUESTED) { + createdGroupId = event.subject().id(); + assertEquals(Group.GroupState.PENDING_ADD, + event.subject().state()); + } else if (expectedEvent == GroupEvent.Type.GROUP_ADDED) { + createdGroupId = event.subject().id(); + assertEquals(Group.GroupState.ADDED, + event.subject().state()); + } else if (expectedEvent == GroupEvent.Type.GROUP_UPDATED) { + createdGroupId = event.subject().id(); + assertEquals(true, + event.subject().buckets(). + buckets().containsAll(createdBuckets.buckets())); + assertEquals(true, + createdBuckets.buckets(). + containsAll(event.subject().buckets().buckets())); + for (GroupBucket bucket:event.subject().buckets().buckets()) { + Optional matched = createdBuckets.buckets() + .stream() + .filter((expected) -> expected.equals(bucket)) + .findFirst(); + assertEquals(matched.get().packets(), + bucket.packets()); + assertEquals(matched.get().bytes(), + bucket.bytes()); + } + assertEquals(Group.GroupState.ADDED, + event.subject().state()); + } else if (expectedEvent == GroupEvent.Type.GROUP_UPDATE_REQUESTED) { + assertEquals(Group.GroupState.PENDING_UPDATE, + event.subject().state()); + } else if (expectedEvent == GroupEvent.Type.GROUP_REMOVE_REQUESTED) { + assertEquals(Group.GroupState.PENDING_DELETE, + event.subject().state()); + } else if (expectedEvent == GroupEvent.Type.GROUP_REMOVED) { + createdGroupId = event.subject().id(); + assertEquals(Group.GroupState.PENDING_DELETE, + event.subject().state()); + } else if (expectedEvent == GroupEvent.Type.GROUP_ADD_FAILED) { + createdGroupId = event.subject().id(); + assertEquals(Group.GroupState.PENDING_ADD, + event.subject().state()); + } else if (expectedEvent == GroupEvent.Type.GROUP_UPDATE_FAILED) { + createdGroupId = event.subject().id(); + assertEquals(Group.GroupState.PENDING_UPDATE, + event.subject().state()); + } else if (expectedEvent == GroupEvent.Type.GROUP_REMOVE_FAILED) { + createdGroupId = event.subject().id(); + assertEquals(Group.GroupState.PENDING_DELETE, + event.subject().state()); + } + } + + public void verifyGroupId(GroupId id) { + assertEquals(createdGroupId, id); + } + } + + /** + * Tests group store operations. The following operations are tested: + * a)Tests device group audit completion status change + * b)Tests storeGroup operation + * c)Tests getGroupCount operation + * d)Tests getGroup operation + * e)Tests getGroups operation + * f)Tests addOrUpdateGroupEntry operation from southbound + * g)Tests updateGroupDescription for ADD operation from northbound + * h)Tests updateGroupDescription for REMOVE operation from northbound + * i)Tests deleteGroupDescription operation from northbound + * j)Tests removeGroupEntry operation from southbound + */ + @Test + public void testGroupStoreOperations() { + // Set the Device AUDIT completed in the store + simpleGroupStore.deviceInitialAuditCompleted(D1, true); + + // Testing storeGroup operation + GroupKey newKey = new DefaultGroupKey("group1".getBytes()); + testStoreAndGetGroup(newKey); + + // Testing addOrUpdateGroupEntry operation from southbound + GroupKey currKey = newKey; + testAddGroupEntryFromSB(currKey); + + // Testing updateGroupDescription for ADD operation from northbound + newKey = new DefaultGroupKey("group1AddBuckets".getBytes()); + testAddBuckets(currKey, newKey); + + // Testing updateGroupDescription for REMOVE operation from northbound + currKey = newKey; + newKey = new DefaultGroupKey("group1RemoveBuckets".getBytes()); + testRemoveBuckets(currKey, newKey); + + // Testing addOrUpdateGroupEntry operation from southbound + currKey = newKey; + testUpdateGroupEntryFromSB(currKey); + + // Testing deleteGroupDescription operation from northbound + testDeleteGroup(currKey); + + // Testing removeGroupEntry operation from southbound + testRemoveGroupFromSB(currKey); + } + + // Testing storeGroup operation + private void testStoreAndGetGroup(GroupKey key) { + PortNumber[] ports = {PortNumber.portNumber(31), + PortNumber.portNumber(32)}; + List outPorts = new ArrayList(); + outPorts.addAll(Arrays.asList(ports)); + + List buckets = new ArrayList(); + for (PortNumber portNumber: outPorts) { + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + tBuilder.setOutput(portNumber) + .setEthDst(MacAddress.valueOf("00:00:00:00:00:02")) + .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) + .pushMpls() + .setMpls(MplsLabel.mplsLabel(106)); + buckets.add(DefaultGroupBucket.createSelectGroupBucket( + tBuilder.build())); + } + GroupBuckets groupBuckets = new GroupBuckets(buckets); + GroupDescription groupDesc = new DefaultGroupDescription( + D1, + Group.Type.SELECT, + groupBuckets, + key, + null, + appId); + InternalGroupStoreDelegate checkStoreGroupDelegate = + new InternalGroupStoreDelegate(key, + groupBuckets, + GroupEvent.Type.GROUP_ADD_REQUESTED); + simpleGroupStore.setDelegate(checkStoreGroupDelegate); + // Testing storeGroup operation + simpleGroupStore.storeGroupDescription(groupDesc); + + // Testing getGroupCount operation + assertEquals(1, simpleGroupStore.getGroupCount(D1)); + + // Testing getGroup operation + Group createdGroup = simpleGroupStore.getGroup(D1, key); + checkStoreGroupDelegate.verifyGroupId(createdGroup.id()); + + // Testing getGroups operation + Iterable createdGroups = simpleGroupStore.getGroups(D1); + int groupCount = 0; + for (Group group:createdGroups) { + checkStoreGroupDelegate.verifyGroupId(group.id()); + groupCount++; + } + assertEquals(1, groupCount); + simpleGroupStore.unsetDelegate(checkStoreGroupDelegate); + } + + // Testing addOrUpdateGroupEntry operation from southbound + private void testAddGroupEntryFromSB(GroupKey currKey) { + Group existingGroup = simpleGroupStore.getGroup(D1, currKey); + + InternalGroupStoreDelegate addGroupEntryDelegate = + new InternalGroupStoreDelegate(currKey, + existingGroup.buckets(), + GroupEvent.Type.GROUP_ADDED); + simpleGroupStore.setDelegate(addGroupEntryDelegate); + simpleGroupStore.addOrUpdateGroupEntry(existingGroup); + simpleGroupStore.unsetDelegate(addGroupEntryDelegate); + } + + // Testing addOrUpdateGroupEntry operation from southbound + private void testUpdateGroupEntryFromSB(GroupKey currKey) { + Group existingGroup = simpleGroupStore.getGroup(D1, currKey); + int totalPkts = 0; + int totalBytes = 0; + List newBucketList = new ArrayList(); + for (GroupBucket bucket:existingGroup.buckets().buckets()) { + StoredGroupBucketEntry newBucket = + (StoredGroupBucketEntry) + DefaultGroupBucket.createSelectGroupBucket(bucket.treatment()); + newBucket.setPackets(10); + newBucket.setBytes(10 * 256 * 8); + totalPkts += 10; + totalBytes += 10 * 256 * 8; + newBucketList.add(newBucket); + } + GroupBuckets updatedBuckets = new GroupBuckets(newBucketList); + Group updatedGroup = new DefaultGroup(existingGroup.id(), + existingGroup.deviceId(), + existingGroup.type(), + updatedBuckets); + ((StoredGroupEntry) updatedGroup).setPackets(totalPkts); + ((StoredGroupEntry) updatedGroup).setBytes(totalBytes); + + InternalGroupStoreDelegate updateGroupEntryDelegate = + new InternalGroupStoreDelegate(currKey, + updatedBuckets, + GroupEvent.Type.GROUP_UPDATED); + simpleGroupStore.setDelegate(updateGroupEntryDelegate); + simpleGroupStore.addOrUpdateGroupEntry(updatedGroup); + simpleGroupStore.unsetDelegate(updateGroupEntryDelegate); + } + + // Testing updateGroupDescription for ADD operation from northbound + private void testAddBuckets(GroupKey currKey, GroupKey addKey) { + Group existingGroup = simpleGroupStore.getGroup(D1, currKey); + List buckets = new ArrayList(); + buckets.addAll(existingGroup.buckets().buckets()); + + PortNumber[] newNeighborPorts = {PortNumber.portNumber(41), + PortNumber.portNumber(42)}; + List newOutPorts = new ArrayList(); + newOutPorts.addAll(Collections.singletonList(newNeighborPorts[0])); + + List toAddBuckets = new ArrayList(); + for (PortNumber portNumber: newOutPorts) { + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + tBuilder.setOutput(portNumber) + .setEthDst(MacAddress.valueOf("00:00:00:00:00:03")) + .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) + .pushMpls() + .setMpls(MplsLabel.mplsLabel(106)); + toAddBuckets.add(DefaultGroupBucket.createSelectGroupBucket( + tBuilder.build())); + } + GroupBuckets toAddGroupBuckets = new GroupBuckets(toAddBuckets); + buckets.addAll(toAddBuckets); + GroupBuckets updatedGroupBuckets = new GroupBuckets(buckets); + InternalGroupStoreDelegate updateGroupDescDelegate = + new InternalGroupStoreDelegate(addKey, + updatedGroupBuckets, + GroupEvent.Type.GROUP_UPDATE_REQUESTED); + simpleGroupStore.setDelegate(updateGroupDescDelegate); + simpleGroupStore.updateGroupDescription(D1, + currKey, + UpdateType.ADD, + toAddGroupBuckets, + addKey); + simpleGroupStore.unsetDelegate(updateGroupDescDelegate); + } + + // Testing updateGroupDescription for REMOVE operation from northbound + private void testRemoveBuckets(GroupKey currKey, GroupKey removeKey) { + Group existingGroup = simpleGroupStore.getGroup(D1, currKey); + List buckets = new ArrayList(); + buckets.addAll(existingGroup.buckets().buckets()); + + List toRemoveBuckets = new ArrayList(); + + // There should be 4 buckets in the current group + toRemoveBuckets.add(buckets.remove(0)); + toRemoveBuckets.add(buckets.remove(1)); + GroupBuckets toRemoveGroupBuckets = new GroupBuckets(toRemoveBuckets); + + GroupBuckets remainingGroupBuckets = new GroupBuckets(buckets); + InternalGroupStoreDelegate removeGroupDescDelegate = + new InternalGroupStoreDelegate(removeKey, + remainingGroupBuckets, + GroupEvent.Type.GROUP_UPDATE_REQUESTED); + simpleGroupStore.setDelegate(removeGroupDescDelegate); + simpleGroupStore.updateGroupDescription(D1, + currKey, + UpdateType.REMOVE, + toRemoveGroupBuckets, + removeKey); + simpleGroupStore.unsetDelegate(removeGroupDescDelegate); + } + + // Testing deleteGroupDescription operation from northbound + private void testDeleteGroup(GroupKey currKey) { + Group existingGroup = simpleGroupStore.getGroup(D1, currKey); + InternalGroupStoreDelegate deleteGroupDescDelegate = + new InternalGroupStoreDelegate(currKey, + existingGroup.buckets(), + GroupEvent.Type.GROUP_REMOVE_REQUESTED); + simpleGroupStore.setDelegate(deleteGroupDescDelegate); + simpleGroupStore.deleteGroupDescription(D1, currKey); + simpleGroupStore.unsetDelegate(deleteGroupDescDelegate); + } + + // Testing removeGroupEntry operation from southbound + private void testRemoveGroupFromSB(GroupKey currKey) { + Group existingGroup = simpleGroupStore.getGroup(D1, currKey); + InternalGroupStoreDelegate removeGroupEntryDelegate = + new InternalGroupStoreDelegate(currKey, + existingGroup.buckets(), + GroupEvent.Type.GROUP_REMOVED); + simpleGroupStore.setDelegate(removeGroupEntryDelegate); + simpleGroupStore.removeGroupEntry(existingGroup); + + // Testing getGroup operation + existingGroup = simpleGroupStore.getGroup(D1, currKey); + assertEquals(null, existingGroup); + assertEquals(0, Iterables.size(simpleGroupStore.getGroups(D1))); + assertEquals(0, simpleGroupStore.getGroupCount(D1)); + + simpleGroupStore.unsetDelegate(removeGroupEntryDelegate); + } + + @Test + public void testGroupOperationFailure() { + + simpleGroupStore.deviceInitialAuditCompleted(D1, true); + + ApplicationId appId = + new DefaultApplicationId(2, "org.groupstore.test"); + GroupKey key = new DefaultGroupKey("group1".getBytes()); + PortNumber[] ports = {PortNumber.portNumber(31), + PortNumber.portNumber(32)}; + List outPorts = new ArrayList(); + outPorts.add(ports[0]); + outPorts.add(ports[1]); + + List buckets = new ArrayList(); + for (PortNumber portNumber: outPorts) { + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + tBuilder.setOutput(portNumber) + .setEthDst(MacAddress.valueOf("00:00:00:00:00:02")) + .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) + .pushMpls() + .setMpls(MplsLabel.mplsLabel(106)); + buckets.add(DefaultGroupBucket.createSelectGroupBucket( + tBuilder.build())); + } + GroupBuckets groupBuckets = new GroupBuckets(buckets); + GroupDescription groupDesc = new DefaultGroupDescription( + D1, + Group.Type.SELECT, + groupBuckets, + key, + null, + appId); + InternalGroupStoreDelegate checkStoreGroupDelegate = + new InternalGroupStoreDelegate(key, + groupBuckets, + GroupEvent.Type.GROUP_ADD_REQUESTED); + simpleGroupStore.setDelegate(checkStoreGroupDelegate); + // Testing storeGroup operation + simpleGroupStore.storeGroupDescription(groupDesc); + simpleGroupStore.unsetDelegate(checkStoreGroupDelegate); + + // Testing Group add operation failure + Group createdGroup = simpleGroupStore.getGroup(D1, key); + checkStoreGroupDelegate.verifyGroupId(createdGroup.id()); + + GroupOperation groupAddOp = GroupOperation. + createAddGroupOperation(createdGroup.id(), + createdGroup.type(), + createdGroup.buckets()); + InternalGroupStoreDelegate checkGroupAddFailureDelegate = + new InternalGroupStoreDelegate(key, + groupBuckets, + GroupEvent.Type.GROUP_ADD_FAILED); + simpleGroupStore.setDelegate(checkGroupAddFailureDelegate); + simpleGroupStore.groupOperationFailed(D1, groupAddOp); + + + // Testing Group modify operation failure + simpleGroupStore.unsetDelegate(checkGroupAddFailureDelegate); + GroupOperation groupModOp = GroupOperation. + createModifyGroupOperation(createdGroup.id(), + createdGroup.type(), + createdGroup.buckets()); + InternalGroupStoreDelegate checkGroupModFailureDelegate = + new InternalGroupStoreDelegate(key, + groupBuckets, + GroupEvent.Type.GROUP_UPDATE_FAILED); + simpleGroupStore.setDelegate(checkGroupModFailureDelegate); + simpleGroupStore.groupOperationFailed(D1, groupModOp); + + // Testing Group modify operation failure + simpleGroupStore.unsetDelegate(checkGroupModFailureDelegate); + GroupOperation groupDelOp = GroupOperation. + createDeleteGroupOperation(createdGroup.id(), + createdGroup.type()); + InternalGroupStoreDelegate checkGroupDelFailureDelegate = + new InternalGroupStoreDelegate(key, + groupBuckets, + GroupEvent.Type.GROUP_REMOVE_FAILED); + simpleGroupStore.setDelegate(checkGroupDelFailureDelegate); + simpleGroupStore.groupOperationFailed(D1, groupDelOp); + } +} + 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 new file mode 100644 index 00000000..f5604f68 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleHostStore.java @@ -0,0 +1,293 @@ +/* + * Copyright 2014 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.trivial; + +import static org.onosproject.net.DefaultAnnotations.merge; +import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED; +import static org.onosproject.net.host.HostEvent.Type.HOST_MOVED; +import static org.onosproject.net.host.HostEvent.Type.HOST_REMOVED; +import static org.onosproject.net.host.HostEvent.Type.HOST_UPDATED; +import static org.slf4j.LoggerFactory.getLogger; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +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.Service; +import org.onosproject.net.Annotations; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.DefaultHost; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Host; +import org.onosproject.net.HostId; +import org.onosproject.net.HostLocation; +import org.onosproject.net.host.HostDescription; +import org.onosproject.net.host.HostEvent; +import org.onosproject.net.host.HostStore; +import org.onosproject.net.host.HostStoreDelegate; +import org.onosproject.net.host.PortAddresses; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.store.AbstractStore; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; +import org.slf4j.Logger; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import com.google.common.collect.SetMultimap; + +// TODO: multi-provider, annotation not supported. +/** + * Manages inventory of end-station hosts using trivial in-memory + * implementation. + */ +@Component(immediate = true) +@Service +public class SimpleHostStore + extends AbstractStore + implements HostStore { + + private final Logger log = getLogger(getClass()); + + // Host inventory + private final Map hosts = new ConcurrentHashMap<>(2000000, 0.75f, 16); + + // Hosts tracked by their location + private final Multimap locations = HashMultimap.create(); + + private final SetMultimap portAddresses = + Multimaps.synchronizedSetMultimap( + HashMultimap.create()); + + @Activate + public void activate() { + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + + @Override + public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId, + HostDescription hostDescription) { + StoredHost host = hosts.get(hostId); + if (host == null) { + return createHost(providerId, hostId, hostDescription); + } + return updateHost(providerId, host, hostDescription); + } + + // creates a new host and sends HOST_ADDED + private HostEvent createHost(ProviderId providerId, HostId hostId, + HostDescription descr) { + StoredHost newhost = new StoredHost(providerId, hostId, + descr.hwAddress(), + descr.vlan(), + descr.location(), + ImmutableSet.copyOf(descr.ipAddress()), + descr.annotations()); + synchronized (this) { + hosts.put(hostId, newhost); + locations.put(descr.location(), newhost); + } + return new HostEvent(HOST_ADDED, newhost); + } + + // checks for type of update to host, sends appropriate event + private HostEvent updateHost(ProviderId providerId, StoredHost host, + HostDescription descr) { + HostEvent event; + if (!host.location().equals(descr.location())) { + host.setLocation(descr.location()); + return new HostEvent(HOST_MOVED, host); + } + + if (host.ipAddresses().containsAll(descr.ipAddress()) && + descr.annotations().keys().isEmpty()) { + return null; + } + + Set addresses = new HashSet<>(host.ipAddresses()); + addresses.addAll(descr.ipAddress()); + Annotations annotations = merge((DefaultAnnotations) host.annotations(), + descr.annotations()); + StoredHost updated = new StoredHost(providerId, host.id(), + host.mac(), host.vlan(), + descr.location(), addresses, + annotations); + event = new HostEvent(HOST_UPDATED, updated); + synchronized (this) { + hosts.put(host.id(), updated); + locations.remove(host.location(), host); + locations.put(updated.location(), updated); + } + return event; + } + + @Override + public HostEvent removeHost(HostId hostId) { + synchronized (this) { + Host host = hosts.remove(hostId); + if (host != null) { + locations.remove((host.location()), host); + return new HostEvent(HOST_REMOVED, host); + } + return null; + } + } + + @Override + public int getHostCount() { + return hosts.size(); + } + + @Override + public Iterable getHosts() { + return ImmutableSet.copyOf(hosts.values()); + } + + @Override + public Host getHost(HostId hostId) { + return hosts.get(hostId); + } + + @Override + public Set getHosts(VlanId vlanId) { + Set vlanset = new HashSet<>(); + for (Host h : hosts.values()) { + if (h.vlan().equals(vlanId)) { + vlanset.add(h); + } + } + return vlanset; + } + + @Override + public Set getHosts(MacAddress mac) { + Set macset = new HashSet<>(); + for (Host h : hosts.values()) { + if (h.mac().equals(mac)) { + macset.add(h); + } + } + return macset; + } + + @Override + public Set getHosts(IpAddress ip) { + Set ipset = new HashSet<>(); + for (Host h : hosts.values()) { + if (h.ipAddresses().contains(ip)) { + ipset.add(h); + } + } + return ipset; + } + + @Override + public Set getConnectedHosts(ConnectPoint connectPoint) { + return ImmutableSet.copyOf(locations.get(connectPoint)); + } + + @Override + public Set getConnectedHosts(DeviceId deviceId) { + Set hostset = new HashSet<>(); + for (ConnectPoint p : locations.keySet()) { + if (p.deviceId().equals(deviceId)) { + hostset.addAll(locations.get(p)); + } + } + return hostset; + } + + @Override + public void updateAddressBindings(PortAddresses addresses) { + portAddresses.put(addresses.connectPoint(), addresses); + } + + @Override + public void removeAddressBindings(PortAddresses addresses) { + portAddresses.remove(addresses.connectPoint(), addresses); + } + + @Override + public void clearAddressBindings(ConnectPoint connectPoint) { + portAddresses.removeAll(connectPoint); + } + + @Override + public Set getAddressBindings() { + synchronized (portAddresses) { + return ImmutableSet.copyOf(portAddresses.values()); + } + } + + @Override + public Set getAddressBindingsForPort(ConnectPoint connectPoint) { + synchronized (portAddresses) { + Set addresses = portAddresses.get(connectPoint); + + if (addresses == null) { + return Collections.emptySet(); + } else { + return ImmutableSet.copyOf(addresses); + } + } + } + + // Auxiliary extension to allow location to mutate. + private static final class StoredHost extends DefaultHost { + private HostLocation location; + + /** + * Creates an end-station host using the supplied information. + * + * @param providerId provider identity + * @param id host identifier + * @param mac host MAC address + * @param vlan host VLAN identifier + * @param location host location + * @param ips host IP addresses + * @param annotations optional key/value annotations + */ + public StoredHost(ProviderId providerId, HostId id, + MacAddress mac, VlanId vlan, HostLocation location, + Set ips, Annotations... annotations) { + super(providerId, id, mac, vlan, location, ips, annotations); + this.location = location; + } + + void setLocation(HostLocation location) { + this.location = location; + } + + @Override + public HostLocation location() { + return location; + } + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleIdBlockStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleIdBlockStore.java new file mode 100644 index 00000000..3f7e563a --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleIdBlockStore.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014 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.trivial; + +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Service; +import org.onosproject.core.IdBlock; +import org.onosproject.core.IdBlockStore; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +/** + * Simple implementation of id block store. + */ +@Component(immediate = true) +@Service +public class SimpleIdBlockStore implements IdBlockStore { + + private static final long DEFAULT_BLOCK_SIZE = 0x1000L; + + private final Map topicBlocks = new ConcurrentHashMap<>(); + + @Override + public synchronized IdBlock getIdBlock(String topic) { + AtomicLong blockGenerator = topicBlocks.get(topic); + if (blockGenerator == null) { + blockGenerator = new AtomicLong(0); + topicBlocks.put(topic, blockGenerator); + } + Long blockBase = blockGenerator.getAndAdd(DEFAULT_BLOCK_SIZE); + return new IdBlock(blockBase, DEFAULT_BLOCK_SIZE); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleIntentStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleIntentStore.java new file mode 100644 index 00000000..9f959663 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleIntentStore.java @@ -0,0 +1,212 @@ +/* + * 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.trivial; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +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.Service; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentData; +import org.onosproject.net.intent.IntentEvent; +import org.onosproject.net.intent.IntentState; +import org.onosproject.net.intent.IntentStore; +import org.onosproject.net.intent.IntentStoreDelegate; +import org.onosproject.net.intent.Key; +import org.onosproject.store.AbstractStore; +import org.slf4j.Logger; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.intent.IntentState.PURGE_REQ; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Simple single-instance implementation of the intent store. + */ +@Component(immediate = true) +@Service +public class SimpleIntentStore + extends AbstractStore + implements IntentStore { + + private final Logger log = getLogger(getClass()); + + private final Map current = Maps.newConcurrentMap(); + private final Map pending = Maps.newConcurrentMap(); + + @Activate + public void activate() { + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + + @Override + public long getIntentCount() { + return current.size(); + } + + @Override + public Iterable getIntents() { + return current.values().stream() + .map(IntentData::intent) + .collect(Collectors.toList()); + } + + @Override + public Iterable getIntentData(boolean localOnly, long olderThan) { + if (localOnly || olderThan > 0) { + long older = System.nanoTime() - olderThan * 1_000_000; //convert ms to ns + final SystemClockTimestamp time = new SystemClockTimestamp(older); + return current.values().stream() + .filter(data -> data.version().isOlderThan(time) && + (!localOnly || isMaster(data.key()))) + .collect(Collectors.toList()); + } + return Lists.newArrayList(current.values()); + } + + @Override + public IntentState getIntentState(Key intentKey) { + IntentData data = current.get(intentKey); + return (data != null) ? data.state() : null; + } + + @Override + public List getInstallableIntents(Key intentKey) { + IntentData data = current.get(intentKey); + if (data != null) { + return data.installables(); + } + return null; + } + + @Override + public void write(IntentData newData) { + checkNotNull(newData); + + synchronized (this) { + // TODO this could be refactored/cleaned up + IntentData currentData = current.get(newData.key()); + IntentData pendingData = pending.get(newData.key()); + + if (IntentData.isUpdateAcceptable(currentData, newData)) { + if (pendingData != null) { + if (pendingData.state() == PURGE_REQ) { + current.remove(newData.key(), newData); + } else { + current.put(newData.key(), new IntentData(newData)); + } + + if (pendingData.version().compareTo(newData.version()) <= 0) { + // pendingData version is less than or equal to newData's + // Note: a new update for this key could be pending (it's version will be greater) + pending.remove(newData.key()); + } + } + notifyDelegateIfNotNull(IntentEvent.getEvent(newData)); + } + } + } + + private void notifyDelegateIfNotNull(IntentEvent event) { + if (event != null) { + notifyDelegate(event); + } + } + + @Override + public void batchWrite(Iterable updates) { + for (IntentData data : updates) { + write(data); + } + } + + @Override + public Intent getIntent(Key key) { + IntentData data = current.get(key); + return (data != null) ? data.intent() : null; + } + + @Override + public IntentData getIntentData(Key key) { + IntentData currentData = current.get(key); + if (currentData == null) { + return null; + } + return new IntentData(currentData); + } + + @Override + public void addPending(IntentData data) { + if (data.version() == null) { // recompiled intents will already have a version + data.setVersion(new SystemClockTimestamp()); + } + synchronized (this) { + IntentData existingData = pending.get(data.key()); + if (existingData == null || + // existing version is strictly less than data's version + // Note: if they are equal, we already have the update + // TODO maybe we should still make this <= to be safe? + existingData.version().compareTo(data.version()) < 0) { + pending.put(data.key(), data); + checkNotNull(delegate, "Store delegate is not set") + .process(new IntentData(data)); + notifyDelegateIfNotNull(IntentEvent.getEvent(data)); + } else { + log.debug("IntentData {} is older than existing: {}", + data, existingData); + } + //TODO consider also checking the current map at this point + } + } + + @Override + public boolean isMaster(Key intentKey) { + return true; + } + + @Override + public Iterable getPending() { + return pending.values().stream() + .map(IntentData::intent) + .collect(Collectors.toList()); + } + + @Override + public Iterable getPendingData() { + return Lists.newArrayList(pending.values()); + } + + @Override + public Iterable getPendingData(boolean localOnly, long olderThan) { + long older = System.nanoTime() - olderThan * 1_000_000; //convert ms to ns + final SystemClockTimestamp time = new SystemClockTimestamp(older); + return pending.values().stream() + .filter(data -> data.version().isOlderThan(time) && + (!localOnly || isMaster(data.key()))) + .collect(Collectors.toList()); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLeadershipManager.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLeadershipManager.java new file mode 100644 index 00000000..194ffec1 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLeadershipManager.java @@ -0,0 +1,135 @@ +/* + * Copyright 2014-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.trivial; + +import static com.google.common.base.Preconditions.checkArgument; + +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.stream.Collectors; + +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; +import org.onosproject.cluster.ClusterService; +import org.onosproject.cluster.Leadership; +import org.onosproject.cluster.LeadershipEvent; +import org.onosproject.cluster.LeadershipEvent.Type; +import org.onosproject.cluster.LeadershipEventListener; +import org.onosproject.cluster.LeadershipService; +import org.onosproject.cluster.NodeId; + +/** + * A trivial implementation of the leadership service. + *

+ * The service is not distributed, so it can assume there's a single leadership + * contender. This contender is always granted leadership whenever it asks. + */ +@Component(immediate = true) +@Service +public class SimpleLeadershipManager implements LeadershipService { + + private Set listeners = new CopyOnWriteArraySet<>(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + private ClusterService clusterService; + + private Map elections = new ConcurrentHashMap<>(); + + @Override + public NodeId getLeader(String path) { + return elections.get(path) ? clusterService.getLocalNode().id() : null; + } + + @Override + public Leadership getLeadership(String path) { + checkArgument(path != null); + return elections.get(path) ? new Leadership(path, clusterService.getLocalNode().id(), 0, 0) : null; + } + + @Override + public Set ownedTopics(NodeId nodeId) { + checkArgument(nodeId != null); + return elections.entrySet() + .stream() + .filter(Entry::getValue) + .map(Entry::getKey) + .collect(Collectors.toSet()); + } + + @Override + public CompletableFuture runForLeadership(String path) { + elections.put(path, true); + for (LeadershipEventListener listener : listeners) { + listener.event(new LeadershipEvent(Type.LEADER_ELECTED, + new Leadership(path, clusterService.getLocalNode().id(), 0, 0))); + } + return CompletableFuture.completedFuture(new Leadership(path, clusterService.getLocalNode().id(), 0, 0)); + } + + @Override + public CompletableFuture withdraw(String path) { + elections.remove(path); + for (LeadershipEventListener listener : listeners) { + listener.event(new LeadershipEvent(Type.LEADER_BOOTED, + new Leadership(path, clusterService.getLocalNode().id(), 0, 0))); + } + return CompletableFuture.completedFuture(null); + } + + @Override + public Map getLeaderBoard() { + //FIXME + throw new UnsupportedOperationException("I don't know what to do." + + " I wish you luck."); + } + + @Override + public void addListener(LeadershipEventListener listener) { + listeners.add(listener); + } + + @Override + public void removeListener(LeadershipEventListener listener) { + listeners.remove(listener); + } + + @Override + public Map> getCandidates() { + return null; + } + + @Override + public List getCandidates(String path) { + return null; + } + + @Override + public boolean stepdown(String path) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean makeTopCandidate(String path, NodeId nodeId) { + throw new UnsupportedOperationException(); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkResourceStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkResourceStore.java new file mode 100644 index 00000000..58b446cf --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkResourceStore.java @@ -0,0 +1,286 @@ +/* + * Copyright 2014-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.trivial; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +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.Service; +import org.onlab.util.Bandwidth; +import org.onlab.util.PositionalParameterStringFormatter; +import org.onosproject.net.AnnotationKeys; +import org.onosproject.net.Annotations; +import org.onosproject.net.Link; +import org.onosproject.net.intent.IntentId; +import org.onosproject.net.resource.link.BandwidthResource; +import org.onosproject.net.resource.link.BandwidthResourceAllocation; +import org.onosproject.net.resource.link.LambdaResource; +import org.onosproject.net.resource.link.LambdaResourceAllocation; +import org.onosproject.net.resource.link.LinkResourceAllocations; +import org.onosproject.net.resource.link.LinkResourceEvent; +import org.onosproject.net.resource.link.LinkResourceStore; +import org.onosproject.net.resource.ResourceAllocation; +import org.onosproject.net.resource.ResourceAllocationException; +import org.onosproject.net.resource.ResourceType; +import org.slf4j.Logger; + +import com.google.common.collect.ImmutableList; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Manages link resources using trivial in-memory structures implementation. + */ +@Component(immediate = true) +@Service +public class SimpleLinkResourceStore implements LinkResourceStore { + private static final BandwidthResource DEFAULT_BANDWIDTH = new BandwidthResource(Bandwidth.mbps(1_000)); + private final Logger log = getLogger(getClass()); + + private Map linkResourceAllocationsMap; + private Map> allocatedResources; + private Map> freeResources; + + @Activate + public void activate() { + linkResourceAllocationsMap = new HashMap<>(); + allocatedResources = new HashMap<>(); + freeResources = new HashMap<>(); + + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + + /** + * Returns free resources for a given link obtaining from topology + * information. + * + * @param link the target link + * @return free resources + */ + private synchronized Set readOriginalFreeResources(Link link) { + Annotations annotations = link.annotations(); + Set allocations = new HashSet<>(); + + try { + int waves = Integer.parseInt(annotations.value(AnnotationKeys.OPTICAL_WAVES)); + for (int i = 1; i <= waves; i++) { + allocations.add(new LambdaResourceAllocation(LambdaResource.valueOf(i))); + } + } catch (NumberFormatException e) { + log.debug("No optical.wave annotation on link %s", link); + } + + BandwidthResource bandwidth = DEFAULT_BANDWIDTH; + try { + bandwidth = new BandwidthResource( + Bandwidth.mbps((Double.parseDouble(annotations.value(AnnotationKeys.BANDWIDTH))))); + } catch (NumberFormatException e) { + log.debug("No bandwidth annotation on link %s", link); + } + allocations.add( + new BandwidthResourceAllocation(bandwidth)); + return allocations; + } + + /** + * Finds and returns {@link BandwidthResourceAllocation} object from a given + * set. + * + * @param freeRes a set of ResourceAllocation object. + * @return {@link BandwidthResourceAllocation} object if found, otherwise + * {@link BandwidthResourceAllocation} object with 0 bandwidth + * + */ + private synchronized BandwidthResourceAllocation getBandwidth( + Set freeRes) { + for (ResourceAllocation res : freeRes) { + if (res.type() == ResourceType.BANDWIDTH) { + return (BandwidthResourceAllocation) res; + } + } + return new BandwidthResourceAllocation(new BandwidthResource(Bandwidth.bps(0))); + } + + /** + * Subtracts given resources from free resources for given link. + * + * @param link the target link + * @param allocations the resources to be subtracted + */ + private synchronized void subtractFreeResources(Link link, + LinkResourceAllocations allocations) { + // TODO Use lock or version for updating freeResources. + checkNotNull(link); + Set freeRes = new HashSet<>(getFreeResources(link)); + Set subRes = allocations.getResourceAllocation(link); + for (ResourceAllocation res : subRes) { + switch (res.type()) { + case BANDWIDTH: + BandwidthResourceAllocation ba = getBandwidth(freeRes); + double requestedBandwidth = + ((BandwidthResourceAllocation) res).bandwidth().toDouble(); + double newBandwidth = ba.bandwidth().toDouble() - requestedBandwidth; + if (newBandwidth < 0.0) { + throw new ResourceAllocationException( + PositionalParameterStringFormatter.format( + "Unable to allocate bandwidth for link {} " + + "requested amount is {} current allocation is {}", + link, + requestedBandwidth, + ba)); + } + freeRes.remove(ba); + freeRes.add(new BandwidthResourceAllocation( + new BandwidthResource(Bandwidth.bps(newBandwidth)))); + break; + case LAMBDA: + final boolean lambdaAvailable = freeRes.remove(res); + if (!lambdaAvailable) { + int requestedLambda = + ((LambdaResourceAllocation) res).lambda().toInt(); + throw new ResourceAllocationException( + PositionalParameterStringFormatter.format( + "Unable to allocate lambda for link {} lambda is {}", + link, + requestedLambda)); + } + break; + default: + break; + } + } + freeResources.put(link, freeRes); + + } + + /** + * Adds given resources to free resources for given link. + * + * @param link the target link + * @param allocations the resources to be added + */ + private synchronized void addFreeResources(Link link, + LinkResourceAllocations allocations) { + // TODO Use lock or version for updating freeResources. + Set freeRes = new HashSet<>(getFreeResources(link)); + Set addRes = allocations.getResourceAllocation(link); + for (ResourceAllocation res : addRes) { + switch (res.type()) { + case BANDWIDTH: + BandwidthResourceAllocation ba = getBandwidth(freeRes); + double requestedBandwidth = + ((BandwidthResourceAllocation) res).bandwidth().toDouble(); + double newBandwidth = ba.bandwidth().toDouble() + requestedBandwidth; + freeRes.remove(ba); + freeRes.add(new BandwidthResourceAllocation( + new BandwidthResource(Bandwidth.bps(newBandwidth)))); + break; + case LAMBDA: + checkState(freeRes.add(res)); + break; + default: + break; + } + } + freeResources.put(link, freeRes); + } + + @Override + public synchronized Set getFreeResources(Link link) { + checkNotNull(link); + Set freeRes = freeResources.get(link); + if (freeRes == null) { + freeRes = readOriginalFreeResources(link); + } + + return freeRes; + } + + @Override + public synchronized void allocateResources(LinkResourceAllocations allocations) { + checkNotNull(allocations); + linkResourceAllocationsMap.put(allocations.intentId(), allocations); + for (Link link : allocations.links()) { + subtractFreeResources(link, allocations); + Set linkAllocs = allocatedResources.get(link); + if (linkAllocs == null) { + linkAllocs = new HashSet<>(); + } + linkAllocs.add(allocations); + allocatedResources.put(link, linkAllocs); + } + } + + @Override + public synchronized LinkResourceEvent releaseResources(LinkResourceAllocations allocations) { + checkNotNull(allocations); + linkResourceAllocationsMap.remove(allocations.intentId()); + for (Link link : allocations.links()) { + addFreeResources(link, allocations); + Set linkAllocs = allocatedResources.get(link); + if (linkAllocs == null) { + log.error("Missing resource allocation."); + } else { + linkAllocs.remove(allocations); + } + allocatedResources.put(link, linkAllocs); + } + + final List releasedResources = + ImmutableList.of(allocations); + + return new LinkResourceEvent( + LinkResourceEvent.Type.ADDITIONAL_RESOURCES_AVAILABLE, + releasedResources); + } + + @Override + public synchronized LinkResourceAllocations getAllocations(IntentId intentId) { + checkNotNull(intentId); + return linkResourceAllocationsMap.get(intentId); + } + + @Override + public synchronized Iterable getAllocations(Link link) { + checkNotNull(link); + Set result = allocatedResources.get(link); + if (result == null) { + result = Collections.emptySet(); + } + return Collections.unmodifiableSet(result); + } + + @Override + public synchronized Iterable getAllocations() { + return Collections.unmodifiableCollection(linkResourceAllocationsMap.values()); + } + + +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkResourceStoreTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkResourceStoreTest.java new file mode 100644 index 00000000..238e75d0 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkResourceStoreTest.java @@ -0,0 +1,307 @@ +/* + * Copyright 2014-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.trivial; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onlab.util.Bandwidth; +import org.onosproject.net.AnnotationKeys; +import org.onosproject.net.Annotations; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.DefaultLink; +import org.onosproject.net.Link; +import org.onosproject.net.intent.IntentId; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.net.resource.link.BandwidthResource; +import org.onosproject.net.resource.link.BandwidthResourceAllocation; +import org.onosproject.net.resource.link.LambdaResource; +import org.onosproject.net.resource.link.LambdaResourceAllocation; +import org.onosproject.net.resource.link.LinkResourceAllocations; +import org.onosproject.net.resource.link.LinkResourceStore; +import org.onosproject.net.resource.ResourceAllocation; +import org.onosproject.net.resource.ResourceAllocationException; +import org.onosproject.net.resource.ResourceRequest; +import org.onosproject.net.resource.ResourceType; + +import com.google.common.collect.ImmutableSet; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.Link.Type.DIRECT; +import static org.onosproject.net.PortNumber.portNumber; + +/** + * Test of the simple LinkResourceStore implementation. + */ +public class SimpleLinkResourceStoreTest { + + private LinkResourceStore store; + private SimpleLinkResourceStore simpleStore; + private Link link1; + private Link link2; + private Link link3; + + /** + * Returns {@link Link} object. + * + * @param dev1 source device + * @param port1 source port + * @param dev2 destination device + * @param port2 destination port + * @return created {@link Link} object + */ + private static Link newLink(String dev1, int port1, String dev2, int port2) { + Annotations annotations = DefaultAnnotations.builder() + .set(AnnotationKeys.OPTICAL_WAVES, "80") + .set(AnnotationKeys.BANDWIDTH, "1000") + .build(); + return new DefaultLink( + new ProviderId("of", "foo"), + new ConnectPoint(deviceId(dev1), portNumber(port1)), + new ConnectPoint(deviceId(dev2), portNumber(port2)), + DIRECT, annotations); + } + + @Before + public void setUp() throws Exception { + simpleStore = new SimpleLinkResourceStore(); + simpleStore.activate(); + store = simpleStore; + + link1 = newLink("of:1", 1, "of:2", 2); + link2 = newLink("of:2", 1, "of:3", 2); + link3 = newLink("of:3", 1, "of:4", 2); + } + + @After + public void tearDown() throws Exception { + simpleStore.deactivate(); + } + + /** + * Tests constructor and activate method. + */ + @Test + public void testConstructorAndActivate() { + final Iterable allAllocations = store.getAllocations(); + assertNotNull(allAllocations); + assertFalse(allAllocations.iterator().hasNext()); + + final Iterable linkAllocations = + store.getAllocations(link1); + assertNotNull(linkAllocations); + assertFalse(linkAllocations.iterator().hasNext()); + + final Set res = store.getFreeResources(link2); + assertNotNull(res); + } + + /** + * Picks up and returns one of bandwidth allocations from a given set. + * + * @param resources the set of {@link ResourceAllocation}s + * @return {@link BandwidthResourceAllocation} object if found, null + * otherwise + */ + private BandwidthResourceAllocation getBandwidthObj(Set resources) { + for (ResourceAllocation res : resources) { + if (res.type() == ResourceType.BANDWIDTH) { + return ((BandwidthResourceAllocation) res); + } + } + return null; + } + + /** + * Returns all lambda allocations from a given set. + * + * @param resources the set of {@link ResourceAllocation}s + * @return a set of {@link LambdaResourceAllocation} objects + */ + private Set getLambdaObjs(Set resources) { + Set lambdaResources = new HashSet<>(); + for (ResourceAllocation res : resources) { + if (res.type() == ResourceType.LAMBDA) { + lambdaResources.add((LambdaResourceAllocation) res); + } + } + return lambdaResources; + } + + /** + * Tests initial free bandwidth for a link. + */ + @Test + public void testInitialBandwidth() { + final Set freeRes = store.getFreeResources(link1); + assertNotNull(freeRes); + + final BandwidthResourceAllocation alloc = getBandwidthObj(freeRes); + assertNotNull(alloc); + + assertEquals(new BandwidthResource(Bandwidth.mbps(1000.0)), alloc.bandwidth()); + } + + /** + * Tests initial free lambda for a link. + */ + @Test + public void testInitialLambdas() { + final Set freeRes = store.getFreeResources(link3); + assertNotNull(freeRes); + + final Set res = getLambdaObjs(freeRes); + assertNotNull(res); + assertEquals(80, res.size()); + } + + public static class MockLinkResourceBandwidthAllocations implements LinkResourceAllocations { + final double allocationAmount; + + MockLinkResourceBandwidthAllocations(Double allocationAmount) { + this.allocationAmount = allocationAmount; + } + @Override + public Set getResourceAllocation(Link link) { + final ResourceAllocation allocation = + new BandwidthResourceAllocation(new BandwidthResource(Bandwidth.bps(allocationAmount))); + final Set allocations = new HashSet<>(); + allocations.add(allocation); + return allocations; + } + + @Override + public IntentId intentId() { + return null; + } + + @Override + public Collection links() { + return ImmutableSet.of(newLink("of:1", 1, "of:2", 2)); + } + + @Override + public Set resources() { + return null; + } + + @Override + public ResourceType type() { + return null; + } + } + + public static class MockLinkResourceLambdaAllocations implements LinkResourceAllocations { + final int allocatedLambda; + + MockLinkResourceLambdaAllocations(int allocatedLambda) { + this.allocatedLambda = allocatedLambda; + } + @Override + public Set getResourceAllocation(Link link) { + final ResourceAllocation allocation = + new LambdaResourceAllocation(LambdaResource.valueOf(allocatedLambda)); + final Set allocations = new HashSet<>(); + allocations.add(allocation); + return allocations; + } + + @Override + public IntentId intentId() { + return null; + } + + @Override + public Collection links() { + return ImmutableSet.of(newLink("of:1", 1, "of:2", 2)); + } + + @Override + public Set resources() { + return null; + } + + @Override + public ResourceType type() { + return null; + } + } + + /** + * Tests a successful bandwidth allocation. + */ + @Test + public void testSuccessfulBandwidthAllocation() { + final LinkResourceAllocations allocations = + new MockLinkResourceBandwidthAllocations(900.0); + store.allocateResources(allocations); + } + + /** + * Tests an unsuccessful bandwidth allocation. + */ + @Test + public void testUnsuccessfulBandwidthAllocation() { + final LinkResourceAllocations allocations = + new MockLinkResourceBandwidthAllocations(2000000000.0); + boolean gotException = false; + try { + store.allocateResources(allocations); + } catch (ResourceAllocationException rae) { + assertEquals(true, rae.getMessage().contains("Unable to allocate bandwidth for link")); + gotException = true; + } + assertEquals(true, gotException); + } + + /** + * Tests a successful lambda allocation. + */ + @Test + public void testSuccessfulLambdaAllocation() { + final LinkResourceAllocations allocations = + new MockLinkResourceLambdaAllocations(1); + store.allocateResources(allocations); + } + + /** + * Tests an unsuccessful lambda allocation. + */ + @Test + public void testUnsuccessfulLambdaAllocation() { + final LinkResourceAllocations allocations = + new MockLinkResourceLambdaAllocations(1); + store.allocateResources(allocations); + + boolean gotException = false; + + try { + store.allocateResources(allocations); + } catch (ResourceAllocationException rae) { + assertEquals(true, rae.getMessage().contains("Unable to allocate lambda for link")); + gotException = true; + } + assertEquals(true, gotException); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkStore.java new file mode 100644 index 00000000..d0be2b1f --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkStore.java @@ -0,0 +1,366 @@ +/* + * Copyright 2014-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.trivial; + +import com.google.common.base.Function; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.Multimaps; +import com.google.common.collect.SetMultimap; +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; +import org.apache.felix.scr.annotations.Service; +import org.onosproject.net.AnnotationKeys; +import org.onosproject.net.AnnotationsUtil; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.DefaultLink; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Link.Type; +import org.onosproject.net.LinkKey; +import org.onosproject.net.SparseAnnotations; +import org.onosproject.net.link.DefaultLinkDescription; +import org.onosproject.net.link.LinkDescription; +import org.onosproject.net.link.LinkEvent; +import org.onosproject.net.link.LinkStore; +import org.onosproject.net.link.LinkStoreDelegate; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.store.AbstractStore; +import org.slf4j.Logger; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static com.google.common.base.Predicates.notNull; +import static com.google.common.base.Verify.verifyNotNull; +import static com.google.common.collect.Multimaps.synchronizedSetMultimap; +import static org.onosproject.net.DefaultAnnotations.merge; +import static org.onosproject.net.DefaultAnnotations.union; +import static org.onosproject.net.Link.State.ACTIVE; +import static org.onosproject.net.Link.State.INACTIVE; +import static org.onosproject.net.Link.Type.DIRECT; +import static org.onosproject.net.Link.Type.INDIRECT; +import static org.onosproject.net.LinkKey.linkKey; +import static org.onosproject.net.link.LinkEvent.Type.*; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Manages inventory of infrastructure links using trivial in-memory structures + * implementation. + */ +@Component(immediate = true) +@Service +public class SimpleLinkStore + extends AbstractStore + implements LinkStore { + + private final Logger log = getLogger(getClass()); + + // Link inventory + private final ConcurrentMap> + linkDescs = new ConcurrentHashMap<>(); + + // Link instance cache + private final ConcurrentMap links = new ConcurrentHashMap<>(); + + // Egress and ingress link sets + private final SetMultimap srcLinks = createSynchronizedHashMultiMap(); + private final SetMultimap dstLinks = createSynchronizedHashMultiMap(); + + + @Activate + public void activate() { + log.info("Started"); + } + + @Deactivate + public void deactivate() { + linkDescs.clear(); + links.clear(); + srcLinks.clear(); + dstLinks.clear(); + log.info("Stopped"); + } + + @Override + public int getLinkCount() { + return links.size(); + } + + @Override + public Iterable getLinks() { + return Collections.unmodifiableCollection(links.values()); + } + + @Override + public Set getDeviceEgressLinks(DeviceId deviceId) { + // lock for iteration + synchronized (srcLinks) { + return FluentIterable.from(srcLinks.get(deviceId)) + .transform(lookupLink()) + .filter(notNull()) + .toSet(); + } + } + + @Override + public Set getDeviceIngressLinks(DeviceId deviceId) { + // lock for iteration + synchronized (dstLinks) { + return FluentIterable.from(dstLinks.get(deviceId)) + .transform(lookupLink()) + .filter(notNull()) + .toSet(); + } + } + + @Override + public Link getLink(ConnectPoint src, ConnectPoint dst) { + return links.get(linkKey(src, dst)); + } + + @Override + public Set getEgressLinks(ConnectPoint src) { + Set egress = new HashSet<>(); + synchronized (srcLinks) { + for (LinkKey linkKey : srcLinks.get(src.deviceId())) { + if (linkKey.src().equals(src)) { + egress.add(links.get(linkKey)); + } + } + } + return egress; + } + + @Override + public Set getIngressLinks(ConnectPoint dst) { + Set ingress = new HashSet<>(); + synchronized (dstLinks) { + for (LinkKey linkKey : dstLinks.get(dst.deviceId())) { + if (linkKey.dst().equals(dst)) { + ingress.add(links.get(linkKey)); + } + } + } + return ingress; + } + + @Override + public LinkEvent createOrUpdateLink(ProviderId providerId, + LinkDescription linkDescription) { + LinkKey key = linkKey(linkDescription.src(), linkDescription.dst()); + + Map descs = getOrCreateLinkDescriptions(key); + synchronized (descs) { + final Link oldLink = links.get(key); + // update description + createOrUpdateLinkDescription(descs, providerId, linkDescription); + final Link newLink = composeLink(descs); + if (oldLink == null) { + return createLink(key, newLink); + } + return updateLink(key, oldLink, newLink); + } + } + + @Override + public LinkEvent removeOrDownLink(ConnectPoint src, ConnectPoint dst) { + Link link = getLink(src, dst); + if (link == null) { + return null; + } + + if (link.isDurable()) { + return link.state() == INACTIVE ? null : + updateLink(linkKey(link.src(), link.dst()), link, + new DefaultLink(link.providerId(), + link.src(), link.dst(), + link.type(), INACTIVE, + link.isDurable(), + link.annotations())); + } + return removeLink(src, dst); + } + + // Guarded by linkDescs value (=locking each Link) + private LinkDescription createOrUpdateLinkDescription( + Map descs, + ProviderId providerId, + LinkDescription linkDescription) { + + // merge existing attributes and merge + LinkDescription oldDesc = descs.get(providerId); + LinkDescription newDesc = linkDescription; + if (oldDesc != null) { + // we only allow transition from INDIRECT -> DIRECT + final Type newType; + if (oldDesc.type() == DIRECT) { + newType = DIRECT; + } else { + newType = linkDescription.type(); + } + SparseAnnotations merged = union(oldDesc.annotations(), + linkDescription.annotations()); + newDesc = new DefaultLinkDescription(linkDescription.src(), + linkDescription.dst(), + newType, merged); + } + return descs.put(providerId, newDesc); + } + + // Creates and stores the link and returns the appropriate event. + // Guarded by linkDescs value (=locking each Link) + private LinkEvent createLink(LinkKey key, Link newLink) { + links.put(key, newLink); + srcLinks.put(newLink.src().deviceId(), key); + dstLinks.put(newLink.dst().deviceId(), key); + return new LinkEvent(LINK_ADDED, newLink); + } + + // Updates, if necessary the specified link and returns the appropriate event. + // Guarded by linkDescs value (=locking each Link) + private LinkEvent updateLink(LinkKey key, Link oldLink, Link newLink) { + if (oldLink.state() != newLink.state() || + (oldLink.type() == INDIRECT && newLink.type() == DIRECT) || + !AnnotationsUtil.isEqual(oldLink.annotations(), newLink.annotations())) { + + links.put(key, newLink); + // strictly speaking following can be ommitted + srcLinks.put(oldLink.src().deviceId(), key); + dstLinks.put(oldLink.dst().deviceId(), key); + return new LinkEvent(LINK_UPDATED, newLink); + } + return null; + } + + @Override + public LinkEvent removeLink(ConnectPoint src, ConnectPoint dst) { + final LinkKey key = linkKey(src, dst); + Map descs = getOrCreateLinkDescriptions(key); + synchronized (descs) { + Link link = links.remove(key); + descs.clear(); + if (link != null) { + srcLinks.remove(link.src().deviceId(), key); + dstLinks.remove(link.dst().deviceId(), key); + return new LinkEvent(LINK_REMOVED, link); + } + return null; + } + } + + /** + * Creates concurrent readable, synchronized HashMultimap. + * + * @return SetMultimap + */ + private static SetMultimap createSynchronizedHashMultiMap() { + return synchronizedSetMultimap( + Multimaps.newSetMultimap(new ConcurrentHashMap>(), + () -> Sets.newConcurrentHashSet())); + } + + /** + * @return primary ProviderID, or randomly chosen one if none exists + */ + // Guarded by linkDescs value (=locking each Link) + private ProviderId getBaseProviderId(Map providerDescs) { + + ProviderId fallBackPrimary = null; + for (Entry e : providerDescs.entrySet()) { + if (!e.getKey().isAncillary()) { + return e.getKey(); + } else if (fallBackPrimary == null) { + // pick randomly as a fallback in case there is no primary + fallBackPrimary = e.getKey(); + } + } + return fallBackPrimary; + } + + // Guarded by linkDescs value (=locking each Link) + private Link composeLink(Map descs) { + ProviderId primary = getBaseProviderId(descs); + LinkDescription base = descs.get(verifyNotNull(primary)); + + ConnectPoint src = base.src(); + ConnectPoint dst = base.dst(); + Type type = base.type(); + DefaultAnnotations annotations = DefaultAnnotations.builder().build(); + annotations = merge(annotations, base.annotations()); + + for (Entry e : descs.entrySet()) { + if (primary.equals(e.getKey())) { + continue; + } + + // TODO: should keep track of Description timestamp + // and only merge conflicting keys when timestamp is newer + // Currently assuming there will never be a key conflict between + // providers + + // annotation merging. not so efficient, should revisit later + annotations = merge(annotations, e.getValue().annotations()); + } + + boolean isDurable = Objects.equals(annotations.value(AnnotationKeys.DURABLE), "true"); + return new DefaultLink(primary, src, dst, type, ACTIVE, isDurable, annotations); + } + + private Map getOrCreateLinkDescriptions(LinkKey key) { + Map r; + r = linkDescs.get(key); + if (r != null) { + return r; + } + r = new HashMap<>(); + final Map concurrentlyAdded; + concurrentlyAdded = linkDescs.putIfAbsent(key, r); + if (concurrentlyAdded == null) { + return r; + } else { + return concurrentlyAdded; + } + } + + private final Function lookupLink = new LookupLink(); + + private Function lookupLink() { + return lookupLink; + } + + private final class LookupLink implements Function { + @Override + public Link apply(LinkKey input) { + if (input == null) { + return null; + } else { + return links.get(input); + } + } + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkStoreTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkStoreTest.java new file mode 100644 index 00000000..2d2b2759 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleLinkStoreTest.java @@ -0,0 +1,542 @@ +/* + * Copyright 2014 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.trivial; + +import com.google.common.collect.Iterables; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.onosproject.net.AnnotationKeys; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Link.Type; +import org.onosproject.net.LinkKey; +import org.onosproject.net.PortNumber; +import org.onosproject.net.SparseAnnotations; +import org.onosproject.net.link.DefaultLinkDescription; +import org.onosproject.net.link.LinkEvent; +import org.onosproject.net.link.LinkStore; +import org.onosproject.net.link.LinkStoreDelegate; +import org.onosproject.net.provider.ProviderId; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.*; +import static org.onosproject.net.DeviceId.deviceId; +import static org.onosproject.net.Link.Type.*; +import static org.onosproject.net.link.LinkEvent.Type.*; +import static org.onosproject.net.NetTestTools.assertAnnotationsEquals; + +/** + * Test of the simple LinkStore implementation. + */ +public class SimpleLinkStoreTest { + + private static final ProviderId PID = new ProviderId("of", "foo"); + private static final ProviderId PIDA = new ProviderId("of", "bar", true); + private static final DeviceId DID1 = deviceId("of:foo"); + private static final DeviceId DID2 = deviceId("of:bar"); + + private static final PortNumber P1 = PortNumber.portNumber(1); + private static final PortNumber P2 = PortNumber.portNumber(2); + private static final PortNumber P3 = PortNumber.portNumber(3); + + private static final SparseAnnotations A1 = DefaultAnnotations.builder() + .set("A1", "a1") + .set("B1", "b1") + .build(); + private static final SparseAnnotations A1_2 = DefaultAnnotations.builder() + .remove("A1") + .set("B3", "b3") + .build(); + private static final SparseAnnotations A2 = DefaultAnnotations.builder() + .set("A2", "a2") + .set("B2", "b2") + .build(); + private static final SparseAnnotations A2_2 = DefaultAnnotations.builder() + .remove("A2") + .set("B4", "b4") + .build(); + + private static final SparseAnnotations DA1 = DefaultAnnotations.builder() + .set("A1", "a1") + .set("B1", "b1") + .set(AnnotationKeys.DURABLE, "true") + .build(); + private static final SparseAnnotations DA2 = DefaultAnnotations.builder() + .set("A2", "a2") + .set("B2", "b2") + .set(AnnotationKeys.DURABLE, "true") + .build(); + private static final SparseAnnotations NDA1 = DefaultAnnotations.builder() + .set("A1", "a1") + .set("B1", "b1") + .remove(AnnotationKeys.DURABLE) + .build(); + + + + private SimpleLinkStore simpleLinkStore; + private LinkStore linkStore; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + simpleLinkStore = new SimpleLinkStore(); + simpleLinkStore.activate(); + linkStore = simpleLinkStore; + } + + @After + public void tearDown() throws Exception { + simpleLinkStore.deactivate(); + } + + private void putLink(DeviceId srcId, PortNumber srcNum, + DeviceId dstId, PortNumber dstNum, + Type type, boolean isDurable, + SparseAnnotations... annotations) { + ConnectPoint src = new ConnectPoint(srcId, srcNum); + ConnectPoint dst = new ConnectPoint(dstId, dstNum); + linkStore.createOrUpdateLink(PID, new DefaultLinkDescription(src, dst, type, + annotations)); + } + + private void putLink(LinkKey key, Type type, SparseAnnotations... annotations) { + putLink(key.src().deviceId(), key.src().port(), + key.dst().deviceId(), key.dst().port(), + type, false, annotations); + } + + private static void assertLink(DeviceId srcId, PortNumber srcNum, + DeviceId dstId, PortNumber dstNum, Type type, + Link link) { + assertEquals(srcId, link.src().deviceId()); + assertEquals(srcNum, link.src().port()); + assertEquals(dstId, link.dst().deviceId()); + assertEquals(dstNum, link.dst().port()); + assertEquals(type, link.type()); + } + + private static void assertLink(LinkKey key, Type type, Link link) { + assertLink(key.src().deviceId(), key.src().port(), + key.dst().deviceId(), key.dst().port(), + type, link); + } + + @Test + public final void testGetLinkCount() { + assertEquals("initialy empty", 0, linkStore.getLinkCount()); + + putLink(DID1, P1, DID2, P2, DIRECT, false); + putLink(DID2, P2, DID1, P1, DIRECT, false); + putLink(DID1, P1, DID2, P2, DIRECT, false); + + assertEquals("expecting 2 unique link", 2, linkStore.getLinkCount()); + } + + @Test + public final void testGetLinks() { + assertEquals("initialy empty", 0, + Iterables.size(linkStore.getLinks())); + + LinkKey linkId1 = LinkKey.linkKey(new ConnectPoint(DID1, P1), new ConnectPoint(DID2, P2)); + LinkKey linkId2 = LinkKey.linkKey(new ConnectPoint(DID2, P2), new ConnectPoint(DID1, P1)); + + putLink(linkId1, DIRECT); + putLink(linkId2, DIRECT); + putLink(linkId1, DIRECT); + + assertEquals("expecting 2 unique link", 2, + Iterables.size(linkStore.getLinks())); + + Map links = new HashMap<>(); + for (Link link : linkStore.getLinks()) { + links.put(LinkKey.linkKey(link), link); + } + + assertLink(linkId1, DIRECT, links.get(linkId1)); + assertLink(linkId2, DIRECT, links.get(linkId2)); + } + + @Test + public final void testGetDeviceEgressLinks() { + LinkKey linkId1 = LinkKey.linkKey(new ConnectPoint(DID1, P1), new ConnectPoint(DID2, P2)); + LinkKey linkId2 = LinkKey.linkKey(new ConnectPoint(DID2, P2), new ConnectPoint(DID1, P1)); + LinkKey linkId3 = LinkKey.linkKey(new ConnectPoint(DID1, P2), new ConnectPoint(DID2, P3)); + + putLink(linkId1, DIRECT); + putLink(linkId2, DIRECT); + putLink(linkId3, DIRECT); + + // DID1,P1 => DID2,P2 + // DID2,P2 => DID1,P1 + // DID1,P2 => DID2,P3 + + Set links1 = linkStore.getDeviceEgressLinks(DID1); + assertEquals(2, links1.size()); + // check + + Set links2 = linkStore.getDeviceEgressLinks(DID2); + assertEquals(1, links2.size()); + assertLink(linkId2, DIRECT, links2.iterator().next()); + } + + @Test + public final void testGetDeviceIngressLinks() { + LinkKey linkId1 = LinkKey.linkKey(new ConnectPoint(DID1, P1), new ConnectPoint(DID2, P2)); + LinkKey linkId2 = LinkKey.linkKey(new ConnectPoint(DID2, P2), new ConnectPoint(DID1, P1)); + LinkKey linkId3 = LinkKey.linkKey(new ConnectPoint(DID1, P2), new ConnectPoint(DID2, P3)); + + putLink(linkId1, DIRECT); + putLink(linkId2, DIRECT); + putLink(linkId3, DIRECT); + + // DID1,P1 => DID2,P2 + // DID2,P2 => DID1,P1 + // DID1,P2 => DID2,P3 + + Set links1 = linkStore.getDeviceIngressLinks(DID2); + assertEquals(2, links1.size()); + // check + + Set links2 = linkStore.getDeviceIngressLinks(DID1); + assertEquals(1, links2.size()); + assertLink(linkId2, DIRECT, links2.iterator().next()); + } + + @Test + public final void testGetLink() { + ConnectPoint src = new ConnectPoint(DID1, P1); + ConnectPoint dst = new ConnectPoint(DID2, P2); + LinkKey linkId1 = LinkKey.linkKey(src, dst); + + putLink(linkId1, DIRECT); + + Link link = linkStore.getLink(src, dst); + assertLink(linkId1, DIRECT, link); + + assertNull("There shouldn't be reverese link", + linkStore.getLink(dst, src)); + } + + @Test + public final void testGetEgressLinks() { + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1); + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2); + LinkKey linkId1 = LinkKey.linkKey(d1P1, d2P2); + LinkKey linkId2 = LinkKey.linkKey(d2P2, d1P1); + LinkKey linkId3 = LinkKey.linkKey(new ConnectPoint(DID1, P2), new ConnectPoint(DID2, P3)); + + putLink(linkId1, DIRECT); + putLink(linkId2, DIRECT); + putLink(linkId3, DIRECT); + + // DID1,P1 => DID2,P2 + // DID2,P2 => DID1,P1 + // DID1,P2 => DID2,P3 + + Set links1 = linkStore.getEgressLinks(d1P1); + assertEquals(1, links1.size()); + assertLink(linkId1, DIRECT, links1.iterator().next()); + + Set links2 = linkStore.getEgressLinks(d2P2); + assertEquals(1, links2.size()); + assertLink(linkId2, DIRECT, links2.iterator().next()); + } + + @Test + public final void testGetIngressLinks() { + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1); + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2); + LinkKey linkId1 = LinkKey.linkKey(d1P1, d2P2); + LinkKey linkId2 = LinkKey.linkKey(d2P2, d1P1); + LinkKey linkId3 = LinkKey.linkKey(new ConnectPoint(DID1, P2), new ConnectPoint(DID2, P3)); + + putLink(linkId1, DIRECT); + putLink(linkId2, DIRECT); + putLink(linkId3, DIRECT); + + // DID1,P1 => DID2,P2 + // DID2,P2 => DID1,P1 + // DID1,P2 => DID2,P3 + + Set links1 = linkStore.getIngressLinks(d2P2); + assertEquals(1, links1.size()); + assertLink(linkId1, DIRECT, links1.iterator().next()); + + Set links2 = linkStore.getIngressLinks(d1P1); + assertEquals(1, links2.size()); + assertLink(linkId2, DIRECT, links2.iterator().next()); + } + + @Test + public final void testCreateOrUpdateLink() { + ConnectPoint src = new ConnectPoint(DID1, P1); + ConnectPoint dst = new ConnectPoint(DID2, P2); + + // add link + LinkEvent event = linkStore.createOrUpdateLink(PID, + new DefaultLinkDescription(src, dst, INDIRECT)); + + assertLink(DID1, P1, DID2, P2, INDIRECT, event.subject()); + assertEquals(LINK_ADDED, event.type()); + + // update link type + LinkEvent event2 = linkStore.createOrUpdateLink(PID, + new DefaultLinkDescription(src, dst, DIRECT)); + + assertLink(DID1, P1, DID2, P2, DIRECT, event2.subject()); + assertEquals(LINK_UPDATED, event2.type()); + + // no change + LinkEvent event3 = linkStore.createOrUpdateLink(PID, + new DefaultLinkDescription(src, dst, DIRECT)); + + assertNull("No change event expected", event3); + } + + @Test + public final void testCreateOrUpdateLinkAncillary() { + ConnectPoint src = new ConnectPoint(DID1, P1); + ConnectPoint dst = new ConnectPoint(DID2, P2); + + // add Ancillary link + LinkEvent event = linkStore.createOrUpdateLink(PIDA, + new DefaultLinkDescription(src, dst, INDIRECT, A1)); + + assertNotNull("Ancillary only link is ignored", event); + + // add Primary link + LinkEvent event2 = linkStore.createOrUpdateLink(PID, + new DefaultLinkDescription(src, dst, INDIRECT, A2)); + + assertLink(DID1, P1, DID2, P2, INDIRECT, event2.subject()); + assertAnnotationsEquals(event2.subject().annotations(), A2, A1); + assertEquals(LINK_UPDATED, event2.type()); + + // update link type + LinkEvent event3 = linkStore.createOrUpdateLink(PID, + new DefaultLinkDescription(src, dst, DIRECT, A2)); + assertLink(DID1, P1, DID2, P2, DIRECT, event3.subject()); + assertAnnotationsEquals(event3.subject().annotations(), A2, A1); + assertEquals(LINK_UPDATED, event3.type()); + + + // no change + LinkEvent event4 = linkStore.createOrUpdateLink(PID, + new DefaultLinkDescription(src, dst, DIRECT)); + assertNull("No change event expected", event4); + + // update link annotation (Primary) + LinkEvent event5 = linkStore.createOrUpdateLink(PID, + new DefaultLinkDescription(src, dst, DIRECT, A2_2)); + assertLink(DID1, P1, DID2, P2, DIRECT, event5.subject()); + assertAnnotationsEquals(event5.subject().annotations(), A2, A2_2, A1); + assertEquals(LINK_UPDATED, event5.type()); + + // update link annotation (Ancillary) + LinkEvent event6 = linkStore.createOrUpdateLink(PIDA, + new DefaultLinkDescription(src, dst, DIRECT, A1_2)); + assertLink(DID1, P1, DID2, P2, DIRECT, event6.subject()); + assertAnnotationsEquals(event6.subject().annotations(), A2, A2_2, A1, A1_2); + assertEquals(LINK_UPDATED, event6.type()); + + // update link type (Ancillary) : ignored + LinkEvent event7 = linkStore.createOrUpdateLink(PIDA, + new DefaultLinkDescription(src, dst, EDGE)); + assertNull("Ancillary change other than annotation is ignored", event7); + } + + + @Test + public final void testRemoveOrDownLink() { + removeOrDownLink(false); + } + + @Test + public final void testRemoveOrDownLinkDurable() { + removeOrDownLink(true); + } + + private void removeOrDownLink(boolean isDurable) { + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1); + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2); + LinkKey linkId1 = LinkKey.linkKey(d1P1, d2P2); + LinkKey linkId2 = LinkKey.linkKey(d2P2, d1P1); + + putLink(linkId1, DIRECT, isDurable ? DA1 : A1); + putLink(linkId2, DIRECT, isDurable ? DA2 : A2); + + // DID1,P1 => DID2,P2 + // DID2,P2 => DID1,P1 + // DID1,P2 => DID2,P3 + + LinkEvent event = linkStore.removeOrDownLink(d1P1, d2P2); + assertEquals(isDurable ? LINK_UPDATED : LINK_REMOVED, event.type()); + assertAnnotationsEquals(event.subject().annotations(), isDurable ? DA1 : A1); + LinkEvent event2 = linkStore.removeOrDownLink(d1P1, d2P2); + assertNull(event2); + + assertLink(linkId2, DIRECT, linkStore.getLink(d2P2, d1P1)); + assertAnnotationsEquals(linkStore.getLink(d2P2, d1P1).annotations(), + isDurable ? DA2 : A2); + + // annotations, etc. should not survive remove + if (!isDurable) { + putLink(linkId1, DIRECT); + assertLink(linkId1, DIRECT, linkStore.getLink(d1P1, d2P2)); + assertAnnotationsEquals(linkStore.getLink(d1P1, d2P2).annotations()); + } + } + + @Test + public final void testRemoveLink() { + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1); + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2); + LinkKey linkId1 = LinkKey.linkKey(d1P1, d2P2); + LinkKey linkId2 = LinkKey.linkKey(d2P2, d1P1); + + putLink(linkId1, DIRECT, A1); + putLink(linkId2, DIRECT, A2); + + // DID1,P1 => DID2,P2 + // DID2,P2 => DID1,P1 + // DID1,P2 => DID2,P3 + + LinkEvent event = linkStore.removeLink(d1P1, d2P2); + assertEquals(LINK_REMOVED, event.type()); + assertAnnotationsEquals(event.subject().annotations(), A1); + LinkEvent event2 = linkStore.removeLink(d1P1, d2P2); + assertNull(event2); + + assertLink(linkId2, DIRECT, linkStore.getLink(d2P2, d1P1)); + assertAnnotationsEquals(linkStore.getLink(d2P2, d1P1).annotations(), A2); + + // annotations, etc. should not survive remove + putLink(linkId1, DIRECT); + assertLink(linkId1, DIRECT, linkStore.getLink(d1P1, d2P2)); + assertAnnotationsEquals(linkStore.getLink(d1P1, d2P2).annotations()); + } + + @Test + public final void testAncillaryVisible() { + ConnectPoint src = new ConnectPoint(DID1, P1); + ConnectPoint dst = new ConnectPoint(DID2, P2); + + // add Ancillary link + linkStore.createOrUpdateLink(PIDA, + new DefaultLinkDescription(src, dst, INDIRECT, A1)); + + // Ancillary only link should not be visible + assertEquals(1, linkStore.getLinkCount()); + assertNotNull(linkStore.getLink(src, dst)); + } + + @Test + public void testDurableToNonDurable() { + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1); + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2); + LinkKey linkId1 = LinkKey.linkKey(d1P1, d2P2); + + putLink(linkId1, DIRECT, DA1); + assertTrue("should be be durable", linkStore.getLink(d1P1, d2P2).isDurable()); + putLink(linkId1, DIRECT, NDA1); + assertFalse("should not be durable", linkStore.getLink(d1P1, d2P2).isDurable()); + } + + @Test + public void testNonDurableToDurable() { + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1); + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2); + LinkKey linkId1 = LinkKey.linkKey(d1P1, d2P2); + + putLink(linkId1, DIRECT, A1); + assertFalse("should not be durable", linkStore.getLink(d1P1, d2P2).isDurable()); + putLink(linkId1, DIRECT, DA1); + assertTrue("should be durable", linkStore.getLink(d1P1, d2P2).isDurable()); + } + + // If Delegates should be called only on remote events, + // then Simple* should never call them, thus not test required. + @Ignore("Ignore until Delegate spec. is clear.") + @Test + public final void testEvents() throws InterruptedException { + + final ConnectPoint d1P1 = new ConnectPoint(DID1, P1); + final ConnectPoint d2P2 = new ConnectPoint(DID2, P2); + final LinkKey linkId1 = LinkKey.linkKey(d1P1, d2P2); + + final CountDownLatch addLatch = new CountDownLatch(1); + LinkStoreDelegate checkAdd = new LinkStoreDelegate() { + @Override + public void notify(LinkEvent event) { + assertEquals(LINK_ADDED, event.type()); + assertLink(linkId1, INDIRECT, event.subject()); + addLatch.countDown(); + } + }; + final CountDownLatch updateLatch = new CountDownLatch(1); + LinkStoreDelegate checkUpdate = new LinkStoreDelegate() { + @Override + public void notify(LinkEvent event) { + assertEquals(LINK_UPDATED, event.type()); + assertLink(linkId1, DIRECT, event.subject()); + updateLatch.countDown(); + } + }; + final CountDownLatch removeLatch = new CountDownLatch(1); + LinkStoreDelegate checkRemove = new LinkStoreDelegate() { + @Override + public void notify(LinkEvent event) { + assertEquals(LINK_REMOVED, event.type()); + assertLink(linkId1, DIRECT, event.subject()); + removeLatch.countDown(); + } + }; + + linkStore.setDelegate(checkAdd); + putLink(linkId1, INDIRECT); + assertTrue("Add event fired", addLatch.await(1, TimeUnit.SECONDS)); + + linkStore.unsetDelegate(checkAdd); + linkStore.setDelegate(checkUpdate); + putLink(linkId1, DIRECT); + assertTrue("Update event fired", updateLatch.await(1, TimeUnit.SECONDS)); + + linkStore.unsetDelegate(checkUpdate); + linkStore.setDelegate(checkRemove); + linkStore.removeOrDownLink(d1P1, d2P2); + assertTrue("Remove event fired", removeLatch.await(1, TimeUnit.SECONDS)); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleMastershipStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleMastershipStore.java new file mode 100644 index 00000000..ef92ded2 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleMastershipStore.java @@ -0,0 +1,388 @@ +/* + * Copyright 2014-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.trivial; + +import static org.onosproject.mastership.MastershipEvent.Type.BACKUPS_CHANGED; +import static org.onosproject.mastership.MastershipEvent.Type.MASTER_CHANGED; +import static org.slf4j.LoggerFactory.getLogger; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicInteger; + +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.joda.time.DateTime; +import org.onlab.packet.IpAddress; +import org.onosproject.cluster.ClusterEventListener; +import org.onosproject.cluster.ClusterService; +import org.onosproject.cluster.ControllerNode; +import org.onosproject.cluster.ControllerNode.State; +import org.onosproject.cluster.DefaultControllerNode; +import org.onosproject.cluster.NodeId; +import org.onosproject.cluster.RoleInfo; +import org.onosproject.mastership.MastershipEvent; +import org.onosproject.mastership.MastershipStore; +import org.onosproject.mastership.MastershipStoreDelegate; +import org.onosproject.mastership.MastershipTerm; +import org.onosproject.net.DeviceId; +import org.onosproject.net.MastershipRole; +import org.onosproject.store.AbstractStore; +import org.slf4j.Logger; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; + +/** + * Manages inventory of controller mastership over devices using + * trivial, non-distributed in-memory structures implementation. + */ +@Component(immediate = true) +@Service +public class SimpleMastershipStore + extends AbstractStore + implements MastershipStore { + + private final Logger log = getLogger(getClass()); + + private static final int NOTHING = 0; + private static final int INIT = 1; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterService clusterService; + + //devices mapped to their masters, to emulate multiple nodes + protected final Map masterMap = new HashMap<>(); + //emulate backups with pile of nodes + protected final Map> backups = new HashMap<>(); + //terms + protected final Map termMap = new HashMap<>(); + + @Activate + public void activate() { + if (clusterService == null) { + // just for ease of unit test + final ControllerNode instance = + new DefaultControllerNode(new NodeId("local"), + IpAddress.valueOf("127.0.0.1")); + + clusterService = new ClusterService() { + + private final DateTime creationTime = DateTime.now(); + + @Override + public ControllerNode getLocalNode() { + return instance; + } + + @Override + public Set getNodes() { + return ImmutableSet.of(instance); + } + + @Override + public ControllerNode getNode(NodeId nodeId) { + if (instance.id().equals(nodeId)) { + return instance; + } + return null; + } + + @Override + public State getState(NodeId nodeId) { + if (instance.id().equals(nodeId)) { + return State.ACTIVE; + } else { + return State.INACTIVE; + } + } + + @Override + public DateTime getLastUpdated(NodeId nodeId) { + return creationTime; + } + + @Override + public void addListener(ClusterEventListener listener) { + } + + @Override + public void removeListener(ClusterEventListener listener) { + } + }; + } + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + + @Override + public synchronized CompletableFuture setMaster(NodeId nodeId, DeviceId deviceId) { + + MastershipRole role = getRole(nodeId, deviceId); + switch (role) { + case MASTER: + // no-op + return CompletableFuture.completedFuture(null); + case STANDBY: + case NONE: + NodeId prevMaster = masterMap.put(deviceId, nodeId); + incrementTerm(deviceId); + removeFromBackups(deviceId, nodeId); + addToBackup(deviceId, prevMaster); + break; + default: + log.warn("unknown Mastership Role {}", role); + return null; + } + + return CompletableFuture.completedFuture( + new MastershipEvent(MASTER_CHANGED, deviceId, getNodes(deviceId))); + } + + @Override + public NodeId getMaster(DeviceId deviceId) { + return masterMap.get(deviceId); + } + + // synchronized for atomic read + @Override + public synchronized RoleInfo getNodes(DeviceId deviceId) { + return new RoleInfo(masterMap.get(deviceId), + backups.getOrDefault(deviceId, ImmutableList.of())); + } + + @Override + public Set getDevices(NodeId nodeId) { + Set ids = new HashSet<>(); + for (Map.Entry d : masterMap.entrySet()) { + if (Objects.equals(d.getValue(), nodeId)) { + ids.add(d.getKey()); + } + } + return ids; + } + + @Override + public synchronized CompletableFuture requestRole(DeviceId deviceId) { + //query+possible reelection + NodeId node = clusterService.getLocalNode().id(); + MastershipRole role = getRole(node, deviceId); + + switch (role) { + case MASTER: + return CompletableFuture.completedFuture(MastershipRole.MASTER); + case STANDBY: + if (getMaster(deviceId) == null) { + // no master => become master + masterMap.put(deviceId, node); + incrementTerm(deviceId); + // remove from backup list + removeFromBackups(deviceId, node); + notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, + getNodes(deviceId))); + return CompletableFuture.completedFuture(MastershipRole.MASTER); + } + return CompletableFuture.completedFuture(MastershipRole.STANDBY); + case NONE: + if (getMaster(deviceId) == null) { + // no master => become master + masterMap.put(deviceId, node); + incrementTerm(deviceId); + notifyDelegate(new MastershipEvent(MASTER_CHANGED, deviceId, + getNodes(deviceId))); + return CompletableFuture.completedFuture(MastershipRole.MASTER); + } + // add to backup list + if (addToBackup(deviceId, node)) { + notifyDelegate(new MastershipEvent(BACKUPS_CHANGED, deviceId, + getNodes(deviceId))); + } + return CompletableFuture.completedFuture(MastershipRole.STANDBY); + default: + log.warn("unknown Mastership Role {}", role); + } + return CompletableFuture.completedFuture(role); + } + + // add to backup if not there already, silently ignores null node + private synchronized boolean addToBackup(DeviceId deviceId, NodeId nodeId) { + boolean modified = false; + List stbys = backups.getOrDefault(deviceId, new ArrayList<>()); + if (nodeId != null && !stbys.contains(nodeId)) { + stbys.add(nodeId); + modified = true; + } + backups.put(deviceId, stbys); + return modified; + } + + private synchronized boolean removeFromBackups(DeviceId deviceId, NodeId node) { + List stbys = backups.getOrDefault(deviceId, new ArrayList<>()); + boolean modified = stbys.remove(node); + backups.put(deviceId, stbys); + return modified; + } + + private synchronized void incrementTerm(DeviceId deviceId) { + AtomicInteger term = termMap.getOrDefault(deviceId, new AtomicInteger(NOTHING)); + term.incrementAndGet(); + termMap.put(deviceId, term); + } + + @Override + public MastershipRole getRole(NodeId nodeId, DeviceId deviceId) { + //just query + NodeId current = masterMap.get(deviceId); + MastershipRole role; + + if (current != null && current.equals(nodeId)) { + return MastershipRole.MASTER; + } + + if (backups.getOrDefault(deviceId, Collections.emptyList()).contains(nodeId)) { + role = MastershipRole.STANDBY; + } else { + role = MastershipRole.NONE; + } + return role; + } + + // synchronized for atomic read + @Override + public synchronized MastershipTerm getTermFor(DeviceId deviceId) { + if ((termMap.get(deviceId) == null)) { + return MastershipTerm.of(masterMap.get(deviceId), NOTHING); + } + return MastershipTerm.of( + masterMap.get(deviceId), termMap.get(deviceId).get()); + } + + @Override + public synchronized CompletableFuture setStandby(NodeId nodeId, DeviceId deviceId) { + MastershipRole role = getRole(nodeId, deviceId); + switch (role) { + case MASTER: + NodeId backup = reelect(deviceId, nodeId); + if (backup == null) { + // no master alternative + masterMap.remove(deviceId); + // TODO: Should there be new event type for no MASTER? + return CompletableFuture.completedFuture( + new MastershipEvent(MASTER_CHANGED, deviceId, getNodes(deviceId))); + } else { + NodeId prevMaster = masterMap.put(deviceId, backup); + incrementTerm(deviceId); + addToBackup(deviceId, prevMaster); + return CompletableFuture.completedFuture( + new MastershipEvent(MASTER_CHANGED, deviceId, getNodes(deviceId))); + } + + case STANDBY: + case NONE: + boolean modified = addToBackup(deviceId, nodeId); + if (modified) { + return CompletableFuture.completedFuture( + new MastershipEvent(BACKUPS_CHANGED, deviceId, getNodes(deviceId))); + } + break; + + default: + log.warn("unknown Mastership Role {}", role); + } + return null; + } + + //dumbly selects next-available node that's not the current one + //emulate leader election + private synchronized NodeId reelect(DeviceId did, NodeId nodeId) { + List stbys = backups.getOrDefault(did, Collections.emptyList()); + NodeId backup = null; + for (NodeId n : stbys) { + if (!n.equals(nodeId)) { + backup = n; + break; + } + } + stbys.remove(backup); + return backup; + } + + @Override + public synchronized CompletableFuture relinquishRole(NodeId nodeId, DeviceId deviceId) { + MastershipRole role = getRole(nodeId, deviceId); + switch (role) { + case MASTER: + NodeId backup = reelect(deviceId, nodeId); + masterMap.put(deviceId, backup); + incrementTerm(deviceId); + return CompletableFuture.completedFuture( + new MastershipEvent(MASTER_CHANGED, deviceId, getNodes(deviceId))); + + case STANDBY: + if (removeFromBackups(deviceId, nodeId)) { + return CompletableFuture.completedFuture( + new MastershipEvent(BACKUPS_CHANGED, deviceId, getNodes(deviceId))); + } + break; + + case NONE: + break; + + default: + log.warn("unknown Mastership Role {}", role); + } + return CompletableFuture.completedFuture(null); + } + + @Override + public synchronized void relinquishAllRole(NodeId nodeId) { + List> eventFutures = new ArrayList<>(); + Set toRelinquish = new HashSet<>(); + + masterMap.entrySet().stream() + .filter(entry -> nodeId.equals(entry.getValue())) + .forEach(entry -> toRelinquish.add(entry.getKey())); + + backups.entrySet().stream() + .filter(entry -> entry.getValue().contains(nodeId)) + .forEach(entry -> toRelinquish.add(entry.getKey())); + + toRelinquish.forEach(deviceId -> { + eventFutures.add(relinquishRole(nodeId, deviceId)); + }); + + eventFutures.forEach(future -> { + future.whenComplete((event, error) -> { + notifyDelegate(event); + }); + }); + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleMastershipStoreTest.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleMastershipStoreTest.java new file mode 100644 index 00000000..672fc503 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleMastershipStoreTest.java @@ -0,0 +1,184 @@ +/* + * Copyright 2014 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.trivial; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.cluster.NodeId; +import org.onosproject.mastership.MastershipEvent; +import org.onosproject.mastership.MastershipTerm; +import org.onosproject.net.DeviceId; + +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.Futures; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.onosproject.mastership.MastershipEvent.Type.*; +import static org.onosproject.net.MastershipRole.*; + +/** + * Test for the simple MastershipStore implementation. + */ +public class SimpleMastershipStoreTest { + + private static final DeviceId DID1 = DeviceId.deviceId("of:01"); + private static final DeviceId DID2 = DeviceId.deviceId("of:02"); + private static final DeviceId DID3 = DeviceId.deviceId("of:03"); + private static final DeviceId DID4 = DeviceId.deviceId("of:04"); + + private static final NodeId N1 = new NodeId("local"); + private static final NodeId N2 = new NodeId("other"); + + private SimpleMastershipStore sms; + + @Before + public void setUp() throws Exception { + sms = new SimpleMastershipStore(); + sms.activate(); + } + + @After + public void tearDown() throws Exception { + sms.deactivate(); + } + + @Test + public void getRole() { + //special case, no backup or master + put(DID1, N1, false, false); + assertEquals("wrong role", NONE, sms.getRole(N1, DID1)); + + //backup exists but we aren't mapped + put(DID2, N1, false, true); + assertEquals("wrong role", STANDBY, sms.getRole(N1, DID2)); + + //N2 is master + put(DID3, N2, true, true); + assertEquals("wrong role", MASTER, sms.getRole(N2, DID3)); + + //N2 is master but N1 is only in backups set + put(DID4, N1, false, true); + put(DID4, N2, true, false); + assertEquals("wrong role", STANDBY, sms.getRole(N1, DID4)); + } + + @Test + public void getMaster() { + put(DID3, N2, true, true); + assertEquals("wrong role", MASTER, sms.getRole(N2, DID3)); + assertEquals("wrong device", N2, sms.getMaster(DID3)); + } + + @Test + public void setMaster() { + put(DID1, N1, false, false); + assertEquals("wrong event", MASTER_CHANGED, Futures.getUnchecked(sms.setMaster(N1, DID1)).type()); + assertEquals("wrong role", MASTER, sms.getRole(N1, DID1)); + //set node that's already master - should be ignored + assertNull("wrong event", Futures.getUnchecked(sms.setMaster(N1, DID1))); + + //set STANDBY to MASTER + put(DID2, N1, false, true); + assertEquals("wrong role", STANDBY, sms.getRole(N1, DID2)); + assertEquals("wrong event", MASTER_CHANGED, Futures.getUnchecked(sms.setMaster(N1, DID2)).type()); + assertEquals("wrong role", MASTER, sms.getRole(N1, DID2)); + } + + @Test + public void getDevices() { + Set d = Sets.newHashSet(DID1, DID2); + + put(DID1, N2, true, true); + put(DID2, N2, true, true); + put(DID3, N1, true, true); + assertTrue("wrong devices", d.equals(sms.getDevices(N2))); + } + + @Test + public void getTermFor() { + put(DID1, N1, true, true); + assertEquals("wrong term", MastershipTerm.of(N1, 0), sms.getTermFor(DID1)); + + //switch to N2 and back - 2 term switches + sms.setMaster(N2, DID1); + sms.setMaster(N1, DID1); + assertEquals("wrong term", MastershipTerm.of(N1, 2), sms.getTermFor(DID1)); + } + + @Test + public void requestRole() { + //NONE - become MASTER + put(DID1, N1, false, false); + assertEquals("wrong role", MASTER, Futures.getUnchecked(sms.requestRole(DID1))); + + //was STANDBY - become MASTER + put(DID2, N1, false, true); + assertEquals("wrong role", MASTER, Futures.getUnchecked(sms.requestRole(DID2))); + + //other MASTER - stay STANDBY + put(DID3, N2, true, false); + assertEquals("wrong role", STANDBY, Futures.getUnchecked(sms.requestRole(DID3))); + + //local (N1) is MASTER - stay MASTER + put(DID4, N1, true, true); + assertEquals("wrong role", MASTER, Futures.getUnchecked(sms.requestRole(DID4))); + } + + @Test + public void unsetMaster() { + //NONE - record backup but take no other action + put(DID1, N1, false, false); + sms.setStandby(N1, DID1); + assertTrue("not backed up", sms.backups.get(DID1).contains(N1)); + int prev = sms.termMap.get(DID1).get(); + sms.setStandby(N1, DID1); + assertEquals("term should not change", prev, sms.termMap.get(DID1).get()); + + //no backup, MASTER + put(DID1, N1, true, false); + assertNull("expect no MASTER event", Futures.getUnchecked(sms.setStandby(N1, DID1)).roleInfo().master()); + assertNull("wrong node", sms.masterMap.get(DID1)); + + //backup, switch + sms.masterMap.clear(); + put(DID1, N1, true, true); + put(DID1, N2, false, true); + put(DID2, N2, true, true); + MastershipEvent event = Futures.getUnchecked(sms.setStandby(N1, DID1)); + assertEquals("wrong event", MASTER_CHANGED, event.type()); + assertEquals("wrong master", N2, event.roleInfo().master()); + } + + //helper to populate master/backup structures + private void put(DeviceId dev, NodeId node, boolean master, boolean backup) { + if (master) { + sms.masterMap.put(dev, node); + } else if (backup) { + List stbys = sms.backups.getOrDefault(dev, new ArrayList<>()); + stbys.add(node); + sms.backups.put(dev, stbys); + } + sms.termMap.put(dev, new AtomicInteger()); + } +} 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 new file mode 100644 index 00000000..4345abaf --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimplePacketStore.java @@ -0,0 +1,64 @@ +/* + * Copyright 2014-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.trivial; + +import com.google.common.collect.Sets; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Service; +import org.onosproject.net.packet.OutboundPacket; +import org.onosproject.net.packet.PacketEvent; +import org.onosproject.net.packet.PacketEvent.Type; +import org.onosproject.net.packet.PacketRequest; +import org.onosproject.net.packet.PacketStore; +import org.onosproject.net.packet.PacketStoreDelegate; +import org.onosproject.store.AbstractStore; + + +import java.util.Collections; +import java.util.Set; + +/** + * Simple single instance implementation of the packet store. + */ +@Component(immediate = true) +@Service +public class SimplePacketStore + extends AbstractStore + implements PacketStore { + + private Set requests = Sets.newConcurrentHashSet(); + + @Override + public void emit(OutboundPacket packet) { + notifyDelegate(new PacketEvent(Type.EMIT, packet)); + } + + @Override + public boolean requestPackets(PacketRequest request) { + return requests.add(request); + } + + @Override + public boolean cancelPackets(PacketRequest request) { + return requests.remove(request); + } + + @Override + public Set existingRequests() { + return Collections.unmodifiableSet(requests); + } + +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleStatisticStore.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleStatisticStore.java new file mode 100644 index 00000000..370686f9 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleStatisticStore.java @@ -0,0 +1,211 @@ +/* + * Copyright 2014-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.trivial; + +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; +import org.apache.felix.scr.annotations.Service; +import org.onosproject.net.ConnectPoint; +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.StatisticStore; +import org.slf4j.Logger; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.slf4j.LoggerFactory.getLogger; + + +/** + * Maintains statistics using RPC calls to collect stats from remote instances + * on demand. + */ +@Component(immediate = true) +@Service +public class SimpleStatisticStore implements StatisticStore { + + private final Logger log = getLogger(getClass()); + + private Map + representations = new ConcurrentHashMap<>(); + + private Map> previous = new ConcurrentHashMap<>(); + private Map> current = new ConcurrentHashMap<>(); + + @Activate + public void activate() { + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + + @Override + public void prepareForStatistics(FlowRule rule) { + ConnectPoint cp = buildConnectPoint(rule); + if (cp == null) { + return; + } + InternalStatisticRepresentation rep; + synchronized (representations) { + rep = getOrCreateRepresentation(cp); + } + rep.prepare(); + } + + @Override + public synchronized void removeFromStatistics(FlowRule rule) { + ConnectPoint cp = buildConnectPoint(rule); + if (cp == null) { + return; + } + InternalStatisticRepresentation rep = representations.get(cp); + if (rep != null && rep.remove(rule)) { + updatePublishedStats(cp, Collections.emptySet()); + } + Set values = current.get(cp); + if (values != null) { + values.remove(rule); + } + values = previous.get(cp); + if (values != null) { + values.remove(rule); + } + + } + + @Override + public void addOrUpdateStatistic(FlowEntry rule) { + ConnectPoint cp = buildConnectPoint(rule); + if (cp == null) { + return; + } + InternalStatisticRepresentation rep = representations.get(cp); + if (rep != null && rep.submit(rule)) { + updatePublishedStats(cp, rep.get()); + } + } + + private synchronized void updatePublishedStats(ConnectPoint cp, + Set flowEntries) { + Set curr = current.get(cp); + if (curr == null) { + curr = new HashSet<>(); + } + previous.put(cp, curr); + current.put(cp, flowEntries); + + } + + @Override + public Set getCurrentStatistic(ConnectPoint connectPoint) { + return getCurrentStatisticInternal(connectPoint); + } + + private synchronized Set getCurrentStatisticInternal(ConnectPoint connectPoint) { + return current.get(connectPoint); + } + + @Override + public Set getPreviousStatistic(ConnectPoint connectPoint) { + return getPreviousStatisticInternal(connectPoint); + } + + private synchronized Set getPreviousStatisticInternal(ConnectPoint connectPoint) { + return previous.get(connectPoint); + } + + private InternalStatisticRepresentation getOrCreateRepresentation(ConnectPoint cp) { + + if (representations.containsKey(cp)) { + return representations.get(cp); + } else { + InternalStatisticRepresentation rep = new InternalStatisticRepresentation(); + representations.put(cp, rep); + return rep; + } + + } + + 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().immediate()) { + 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; + } + + private class InternalStatisticRepresentation { + + private final AtomicInteger counter = new AtomicInteger(0); + private final Set rules = new HashSet<>(); + + public void prepare() { + counter.incrementAndGet(); + } + + public synchronized boolean remove(FlowRule rule) { + rules.remove(rule); + return counter.decrementAndGet() == 0; + } + + public synchronized boolean submit(FlowEntry rule) { + if (rules.contains(rule)) { + rules.remove(rule); + } + rules.add(rule); + if (counter.get() == 0) { + return true; + } else { + return counter.decrementAndGet() == 0; + } + } + + public synchronized Set get() { + counter.set(rules.size()); + return Sets.newHashSet(rules); + } + + } + +} 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 new file mode 100644 index 00000000..6a89c019 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SimpleTopologyStore.java @@ -0,0 +1,157 @@ +/* + * Copyright 2014 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.trivial; + +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.Service; +import org.onosproject.common.DefaultTopology; +import org.onosproject.event.Event; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.net.topology.ClusterId; +import org.onosproject.net.topology.GraphDescription; +import org.onosproject.net.topology.LinkWeight; +import org.onosproject.net.topology.Topology; +import org.onosproject.net.topology.TopologyCluster; +import org.onosproject.net.topology.TopologyEvent; +import org.onosproject.net.topology.TopologyGraph; +import org.onosproject.net.topology.TopologyStore; +import org.onosproject.net.topology.TopologyStoreDelegate; +import org.onosproject.store.AbstractStore; +import org.slf4j.Logger; + +import java.util.List; +import java.util.Set; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Manages inventory of topology snapshots using trivial in-memory + * structures implementation. + */ +@Component(immediate = true) +@Service +public class SimpleTopologyStore + extends AbstractStore + implements TopologyStore { + + private final Logger log = getLogger(getClass()); + + private volatile DefaultTopology current; + + @Activate + public void activate() { + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + @Override + public Topology currentTopology() { + return current; + } + + @Override + public boolean isLatest(Topology topology) { + // Topology is current only if it is the same as our current topology + return topology == current; + } + + @Override + public TopologyGraph getGraph(Topology topology) { + return defaultTopology(topology).getGraph(); + } + + @Override + public Set getClusters(Topology topology) { + return defaultTopology(topology).getClusters(); + } + + @Override + public TopologyCluster getCluster(Topology topology, ClusterId clusterId) { + return defaultTopology(topology).getCluster(clusterId); + } + + @Override + public Set getClusterDevices(Topology topology, TopologyCluster cluster) { + return defaultTopology(topology).getClusterDevices(cluster); + } + + @Override + public Set getClusterLinks(Topology topology, TopologyCluster cluster) { + return defaultTopology(topology).getClusterLinks(cluster); + } + + @Override + public Set getPaths(Topology topology, DeviceId src, DeviceId dst) { + return defaultTopology(topology).getPaths(src, dst); + } + + @Override + public Set getPaths(Topology topology, DeviceId src, DeviceId dst, + LinkWeight weight) { + return defaultTopology(topology).getPaths(src, dst, weight); + } + + @Override + public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) { + return defaultTopology(topology).isInfrastructure(connectPoint); + } + + @Override + public boolean isBroadcastPoint(Topology topology, ConnectPoint connectPoint) { + return defaultTopology(topology).isBroadcastPoint(connectPoint); + } + + @Override + public TopologyEvent updateTopology(ProviderId providerId, + GraphDescription graphDescription, + List reasons) { + // First off, make sure that what we're given is indeed newer than + // what we already have. + if (current != null && graphDescription.timestamp() < current.time()) { + return null; + } + + // Have the default topology construct self from the description data. + DefaultTopology newTopology = + new DefaultTopology(providerId, graphDescription); + + // Promote the new topology to current and return a ready-to-send event. + synchronized (this) { + current = newTopology; + return new TopologyEvent(TopologyEvent.Type.TOPOLOGY_CHANGED, + current, reasons); + } + } + + // Validates the specified topology and returns it as a default + private DefaultTopology defaultTopology(Topology topology) { + if (topology instanceof DefaultTopology) { + return (DefaultTopology) topology; + } + throw new IllegalArgumentException("Topology class " + topology.getClass() + + " not supported"); + } + +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SystemClockTimestamp.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SystemClockTimestamp.java new file mode 100644 index 00000000..2ee41945 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/SystemClockTimestamp.java @@ -0,0 +1,83 @@ +/* + * 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.trivial; + +import com.google.common.base.MoreObjects; +import com.google.common.collect.ComparisonChain; +import org.onosproject.store.Timestamp; + +import java.util.Objects; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * A Timestamp that derives its value from the system clock time (in ns) + * on the controller where it is generated. + */ +public class SystemClockTimestamp implements Timestamp { + + private final long nanoTimestamp; + + public SystemClockTimestamp() { + nanoTimestamp = System.nanoTime(); + } + + public SystemClockTimestamp(long timestamp) { + nanoTimestamp = timestamp; + } + + @Override + public int compareTo(Timestamp o) { + checkArgument(o instanceof SystemClockTimestamp, + "Must be SystemClockTimestamp", o); + SystemClockTimestamp that = (SystemClockTimestamp) o; + + return ComparisonChain.start() + .compare(this.nanoTimestamp, that.nanoTimestamp) + .result(); + } + @Override + public int hashCode() { + return Objects.hash(nanoTimestamp); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof SystemClockTimestamp)) { + return false; + } + SystemClockTimestamp that = (SystemClockTimestamp) obj; + return Objects.equals(this.nanoTimestamp, that.nanoTimestamp); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(getClass()) + .add("nanoTimestamp", nanoTimestamp) + .toString(); + } + + public long nanoTimestamp() { + return nanoTimestamp; + } + + public long systemTimestamp() { + return nanoTimestamp / 1_000_000; // convert ns to ms + } +} diff --git a/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/package-info.java b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/package-info.java new file mode 100644 index 00000000..2b0c36b8 --- /dev/null +++ b/framework/src/onos/core/common/src/test/java/org/onosproject/store/trivial/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2014 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. + */ + +/** + * Implementations of in-memory stores suitable for unit testing and + * experimentation; not for production use. + */ +package org.onosproject.store.trivial; diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/AnnotationConstraint.json b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/AnnotationConstraint.json new file mode 100644 index 00000000..aaa72a72 --- /dev/null +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/AnnotationConstraint.json @@ -0,0 +1,5 @@ +{ + "type":"AnnotationConstraint", + "key":"key", + "threshold":123.0 +} diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/AsymmetricPathConstraint.json b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/AsymmetricPathConstraint.json new file mode 100644 index 00000000..340bdbac --- /dev/null +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/AsymmetricPathConstraint.json @@ -0,0 +1,3 @@ +{ + "type":"AsymmetricPathConstraint" +} diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/BandwidthConstraint.json b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/BandwidthConstraint.json new file mode 100644 index 00000000..34750061 --- /dev/null +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/BandwidthConstraint.json @@ -0,0 +1,4 @@ +{ + "type":"BandwidthConstraint", + "bandwidth":345.678 +} diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/HostToHostIntent.json b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/HostToHostIntent.json new file mode 100644 index 00000000..fedea251 --- /dev/null +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/HostToHostIntent.json @@ -0,0 +1,19 @@ +{ + "type": "HostToHostIntent", + "appId": "test", + "selector": {"criteria": []}, + "treatment": { + "instructions": [], + "deferred": [] + }, + "priority": 7, + "constraints": [ + { + "inclusive": false, + "types": ["OPTICAL"], + "type": "LinkTypeConstraint" + } + ], + "one": "00:00:00:00:00:02/-1", + "two": "00:00:00:00:00:05/-1" +} diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/LambdaConstraint.json b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/LambdaConstraint.json new file mode 100644 index 00000000..4ac37631 --- /dev/null +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/LambdaConstraint.json @@ -0,0 +1,4 @@ +{ + "type":"LambdaConstraint", + "lambda":444 +} diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/LatencyConstraint.json b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/LatencyConstraint.json new file mode 100644 index 00000000..1c46e5e8 --- /dev/null +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/LatencyConstraint.json @@ -0,0 +1,4 @@ +{ + "type":"LatencyConstraint", + "latencyMillis":111 +} diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/LinkTypeConstraint.json b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/LinkTypeConstraint.json new file mode 100644 index 00000000..8b766da0 --- /dev/null +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/LinkTypeConstraint.json @@ -0,0 +1,5 @@ +{ + "inclusive":false, + "types":["DIRECT","OPTICAL"], + "type":"LinkTypeConstraint" +} diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/ObstacleConstraint.json b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/ObstacleConstraint.json new file mode 100644 index 00000000..35dcb0fe --- /dev/null +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/ObstacleConstraint.json @@ -0,0 +1,4 @@ +{ + "type":"ObstacleConstraint", + "obstacles":["of:dev1","of:dev2","of:dev3"] +} diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/PointToPointIntent.json b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/PointToPointIntent.json new file mode 100644 index 00000000..b941bef8 --- /dev/null +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/PointToPointIntent.json @@ -0,0 +1,38 @@ +{ + "type": "PointToPointIntent", + "appId": "test", + "selector": { + "criteria": [ + { + "type": "ETH_DST", + "mac": "11:22:33:44:55:66" + } + ] + }, + "treatment": { + "instructions": [ + { + "type": "L2MODIFICATION", + "subtype": "ETH_SRC", + "mac": "22:33:44:55:66:77" + } + ], + "deferred": [] + }, + "priority": 55, + "constraints": [ + { + "inclusive": false, + "types": ["OPTICAL"], + "type": "LinkTypeConstraint" + } + ], + "ingressPoint": { + "port": "1", + "device": "of:0000000000000001" + }, + "egressPoint": { + "port": "2", + "device": "of:0000000000000007" + } +} diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/WaypointConstraint.json b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/WaypointConstraint.json new file mode 100644 index 00000000..7009cf98 --- /dev/null +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/WaypointConstraint.json @@ -0,0 +1,4 @@ +{ + "type":"WaypointConstraint", + "waypoints":["of:devA","of:devB","of:devC"] +} diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/criteria-flow.json b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/criteria-flow.json new file mode 100644 index 00000000..1a96e92f --- /dev/null +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/criteria-flow.json @@ -0,0 +1,44 @@ +{ + "priority":1, + "isPermanent":"false", + "timeout":1, + "deviceId":"of:0000000000000001", + "selector": + {"criteria": + [ + {"type":"IN_PORT", "port":23}, + {"type":"IN_PHY_PORT", "port":44}, + {"type":"METADATA", "metadata":123456}, + {"type":"ETH_TYPE","ethType":2054}, + {"type":"ETH_SRC","mac":"00:11:22:33:44:55"}, + {"type":"ETH_DST","mac":"00:11:22:33:44:55"}, + {"type":"VLAN_VID","vlanId":777}, + {"type":"VLAN_PCP","priority":3}, + {"type":"IP_DSCP","ipDscp":2}, + {"type":"IP_ECN","ipEcn":1}, + {"type":"IP_PROTO","protocol":4}, + {"type":"IPV4_SRC", "ip":"1.2.0.0/32"}, + {"type":"IPV4_DST", "ip":"2.2.0.0/32"}, + {"type":"IPV6_SRC", "ip":"3.2.0.0/32"}, + {"type":"IPV6_DST", "ip":"4.2.0.0/32"}, + {"type":"TCP_SRC", "tcpPort":80}, + {"type":"TCP_DST", "tcpPort":443}, + {"type":"UDP_SRC", "udpPort":180}, + {"type":"UDP_DST", "udpPort":1443}, + {"type":"SCTP_SRC", "sctpPort":280}, + {"type":"SCTP_DST", "sctpPort":2443}, + {"type":"ICMPV4_TYPE", "icmpType":24}, + {"type":"ICMPV4_CODE", "icmpCode":16}, + {"type":"ICMPV6_TYPE", "icmpv6Type":14}, + {"type":"ICMPV6_CODE", "icmpv6Code":6}, + {"type":"IPV6_FLABEL", "flowLabel":8}, + {"type":"IPV6_ND_TARGET", "targetAddress":"1111:2222:3333:4444:5555:6666:7777:8888"}, + {"type":"IPV6_ND_SLL", "mac":"00:11:22:33:44:56"}, + {"type":"IPV6_ND_TLL", "mac":"00:11:22:33:44:57"}, + {"type":"MPLS_LABEL", "label":123}, + {"type":"IPV6_EXTHDR", "exthdrFlags":99}, + {"type":"OCH_SIGID", "lambda":122}, + {"type":"TUNNEL_ID", "tunnelId":100} + ] + } +} diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/instructions-flow.json b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/instructions-flow.json new file mode 100644 index 00000000..74b9546a --- /dev/null +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/instructions-flow.json @@ -0,0 +1,39 @@ +{ + "priority":1, + "isPermanent":"false", + "timeout":1, + "deviceId":"of:0000000000000001", + "treatment": + { + "instructions": + [ + {"type":"OUTPUT","port":-3}, + {"type":"DROP"}, + {"type":"L2MODIFICATION","subtype":"ETH_SRC","mac":"12:34:56:78:90:12"}, + {"type":"L2MODIFICATION","subtype":"ETH_DST","mac":"98:76:54:32:01:00"}, + {"type":"L2MODIFICATION","subtype":"VLAN_ID","vlanId":22}, + {"type":"L2MODIFICATION","subtype":"VLAN_PCP","vlanPcp":1}, + {"type":"L2MODIFICATION","subtype":"MPLS_LABEL","label":1048575}, + {"type":"L2MODIFICATION","subtype":"MPLS_PUSH"}, + {"type":"L2MODIFICATION","subtype":"MPLS_POP"}, + {"type":"L2MODIFICATION","subtype":"DEC_MPLS_TTL"}, + {"type":"L2MODIFICATION","subtype":"VLAN_POP"}, + {"type":"L2MODIFICATION","subtype":"VLAN_PUSH"}, + {"type":"L2MODIFICATION","subtype":"TUNNEL_ID", "tunnelId":100}, + {"type":"L3MODIFICATION","subtype":"IPV4_SRC", "ip":"1.2.3.4"}, + {"type":"L3MODIFICATION","subtype":"IPV4_DST", "ip":"1.2.3.3"}, + {"type":"L3MODIFICATION","subtype":"IPV6_SRC", "ip":"1.2.3.2"}, + {"type":"L3MODIFICATION","subtype":"IPV6_DST", "ip":"1.2.3.1"}, + {"type":"L3MODIFICATION","subtype":"IPV6_FLABEL", "flowLabel":8}, + {"type":"L0MODIFICATION","subtype":"LAMBDA","lambda":7}, + {"type":"L0MODIFICATION","subtype":"OCH","gridType":"DWDM", + "channelSpacing":"CHL_100GHZ","spacingMultiplier":4,"slotGranularity":8}, + {"type":"L4MODIFICATION","subtype":"TCP_DST","tcpPort":40001}, + {"type":"L4MODIFICATION","subtype":"TCP_SRC","tcpPort":40002}, + {"type":"L4MODIFICATION","subtype":"UDP_DST","udpPort":40003}, + {"type":"L4MODIFICATION","subtype":"UDP_SRC","udpPort":40004} + ], + "deferred":[] + }, + "selector": {"criteria":[{"type":"ETH_TYPE","ethType":2054}]} +} diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/sigid-flow.json b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/sigid-flow.json new file mode 100644 index 00000000..49d6b1ce --- /dev/null +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/sigid-flow.json @@ -0,0 +1,20 @@ +{ + "priority":1, + "isPermanent":"false", + "timeout":1, + "deviceId":"of:0000000000000001", + "selector": + {"criteria": + [ + {"type":"OCH_SIGID", + "ochSignalId": + { + "gridType":"CWDM", + "channelSpacing":"CHL_25GHZ", + "spacingMultiplier":3, + "slotGranularity":4 + } + } + ] + } +} diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/simple-flow.json b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/simple-flow.json new file mode 100644 index 00000000..dc241f55 --- /dev/null +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/codec/impl/simple-flow.json @@ -0,0 +1,12 @@ +{ + "priority":1, + "isPermanent":"false", + "timeout":1, + "deviceId":"of:0000000000000001", + "treatment": + {"instructions": + [{"type":"OUTPUT","port":-3}],"deferred":[]}, + "selector": + {"criteria": + [{"type":"ETH_TYPE","ethType":2054}]} +} diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/common/app/app.xml b/framework/src/onos/core/common/src/test/resources/org/onosproject/common/app/app.xml new file mode 100644 index 00000000..0d91a735 --- /dev/null +++ b/framework/src/onos/core/common/src/test/resources/org/onosproject/common/app/app.xml @@ -0,0 +1,29 @@ + + + Awesome application from Circus, Inc. + + ADMIN + + FLOWRULE_WRITE + FLOWRULE_READ + + + + + diff --git a/framework/src/onos/core/common/src/test/resources/org/onosproject/common/app/app.zip b/framework/src/onos/core/common/src/test/resources/org/onosproject/common/app/app.zip new file mode 100644 index 00000000..436cd755 Binary files /dev/null and b/framework/src/onos/core/common/src/test/resources/org/onosproject/common/app/app.zip differ diff --git a/framework/src/onos/core/net/pom.xml b/framework/src/onos/core/net/pom.xml new file mode 100644 index 00000000..4ba04c50 --- /dev/null +++ b/framework/src/onos/core/net/pom.xml @@ -0,0 +1,98 @@ + + + + 4.0.0 + + + org.onosproject + onos-core + 1.3.0-SNAPSHOT + ../pom.xml + + + onos-core-net + bundle + + ONOS network control core subsystems + + + + org.onosproject + onos-api + + + + org.onosproject + onos-api + tests + test + + + + org.onosproject + onos-core-common + ${project.version} + + + + org.onosproject + onos-core-common + ${project.version} + tests + test + + + + org.onosproject + onos-core-dist + ${project.version} + test + + + + org.onosproject + onos-incubator-api + test + tests + ${project.version} + + + + org.easymock + easymock + test + + + + org.onosproject + onos-incubator-api + + + + org.apache.karaf.features + org.apache.karaf.features.core + + + + org.apache.karaf.system + org.apache.karaf.system.core + + + + diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java new file mode 100644 index 00000000..161659f9 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java @@ -0,0 +1,250 @@ +/* + * 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.app.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.apache.karaf.features.Feature; +import org.apache.karaf.features.FeaturesService; +import org.onosproject.app.ApplicationAdminService; +import org.onosproject.app.ApplicationEvent; +import org.onosproject.app.ApplicationListener; +import org.onosproject.app.ApplicationService; +import org.onosproject.app.ApplicationState; +import org.onosproject.app.ApplicationStore; +import org.onosproject.app.ApplicationStoreDelegate; +import org.onosproject.event.AbstractListenerManager; +import org.onosproject.core.Application; +import org.onosproject.core.ApplicationId; +import org.onosproject.security.Permission; +import org.onosproject.security.SecurityUtil; +import org.slf4j.Logger; + +import java.io.InputStream; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.app.ApplicationEvent.Type.*; +import static org.onosproject.security.AppPermission.Type.*; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Implementation of the application management service. + */ +@Component(immediate = true) +@Service +public class ApplicationManager + extends AbstractListenerManager + implements ApplicationService, ApplicationAdminService { + + private final Logger log = getLogger(getClass()); + + private static final String APP_ID_NULL = "Application ID cannot be null"; + + private final ApplicationStoreDelegate delegate = new InternalStoreDelegate(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ApplicationStore store; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected FeaturesService featuresService; + + private boolean initializing; + + @Activate + public void activate() { + eventDispatcher.addSink(ApplicationEvent.class, listenerRegistry); + + initializing = true; + store.setDelegate(delegate); + initializing = false; + + log.info("Started"); + } + + @Deactivate + public void deactivate() { + eventDispatcher.removeSink(ApplicationEvent.class); + store.unsetDelegate(delegate); + log.info("Stopped"); + } + + @Override + public Set getApplications() { + checkPermission(APP_READ); + return store.getApplications(); + } + + @Override + public ApplicationId getId(String name) { + checkPermission(APP_READ); + checkNotNull(name, "Name cannot be null"); + return store.getId(name); + } + + @Override + public Application getApplication(ApplicationId appId) { + checkPermission(APP_READ); + checkNotNull(appId, APP_ID_NULL); + return store.getApplication(appId); + } + + @Override + public ApplicationState getState(ApplicationId appId) { + checkPermission(APP_READ); + checkNotNull(appId, APP_ID_NULL); + return store.getState(appId); + } + + @Override + public Set getPermissions(ApplicationId appId) { + checkPermission(APP_READ); + checkNotNull(appId, APP_ID_NULL); + return store.getPermissions(appId); + } + + @Override + public Application install(InputStream appDescStream) { + checkNotNull(appDescStream, "Application archive stream cannot be null"); + Application app = store.create(appDescStream); + SecurityUtil.register(app.id()); + return app; + } + + @Override + public void uninstall(ApplicationId appId) { + checkNotNull(appId, APP_ID_NULL); + try { + store.remove(appId); + } catch (Exception e) { + log.warn("Unable to purge application directory for {}", appId.name()); + } + } + + @Override + public void activate(ApplicationId appId) { + checkNotNull(appId, APP_ID_NULL); + if (!SecurityUtil.isAppSecured(appId)) { + return; + } + store.activate(appId); + } + + @Override + public void deactivate(ApplicationId appId) { + checkNotNull(appId, APP_ID_NULL); + store.deactivate(appId); + } + + @Override + public void setPermissions(ApplicationId appId, Set permissions) { + checkNotNull(appId, APP_ID_NULL); + checkNotNull(permissions, "Permissions cannot be null"); + store.setPermissions(appId, permissions); + } + + private class InternalStoreDelegate implements ApplicationStoreDelegate { + @Override + public void notify(ApplicationEvent event) { + ApplicationEvent.Type type = event.type(); + Application app = event.subject(); + try { + if (type == APP_ACTIVATED) { + if (installAppFeatures(app)) { + log.info("Application {} has been activated", app.id().name()); + } + + } else if (type == APP_DEACTIVATED) { + if (uninstallAppFeatures(app)) { + log.info("Application {} has been deactivated", app.id().name()); + } + + } else if (type == APP_INSTALLED) { + if (installAppArtifacts(app)) { + log.info("Application {} has been installed", app.id().name()); + } + + } else if (type == APP_UNINSTALLED) { + if (uninstallAppFeatures(app) || uninstallAppArtifacts(app)) { + log.info("Application {} has been uninstalled", app.id().name()); + } + + } + post(event); + + } catch (Exception e) { + log.warn("Unable to perform operation on application " + app.id().name(), e); + } + } + } + + // The following methods are fully synchronized to guard against remote vs. + // locally induced feature service interactions. + + private synchronized boolean installAppArtifacts(Application app) throws Exception { + if (app.featuresRepo().isPresent() && + featuresService.getRepository(app.featuresRepo().get()) == null) { + featuresService.addRepository(app.featuresRepo().get()); + return true; + } + return false; + } + + private synchronized boolean uninstallAppArtifacts(Application app) throws Exception { + if (app.featuresRepo().isPresent() && + featuresService.getRepository(app.featuresRepo().get()) != null) { + featuresService.removeRepository(app.featuresRepo().get()); + return true; + } + return false; + } + + private synchronized boolean installAppFeatures(Application app) throws Exception { + boolean changed = false; + for (String name : app.features()) { + Feature feature = featuresService.getFeature(name); + if (feature != null && !featuresService.isInstalled(feature)) { + featuresService.installFeature(name); + changed = true; + } else if (feature == null && !initializing) { + // Suppress feature-not-found reporting during startup since these + // can arise naturally from the staggered cluster install. + log.warn("Feature {} not found", name); + } + } + return changed; + } + + private synchronized boolean uninstallAppFeatures(Application app) throws Exception { + boolean changed = false; + for (String name : app.features()) { + Feature feature = featuresService.getFeature(name); + if (feature != null && featuresService.isInstalled(feature)) { + featuresService.uninstallFeature(name); + changed = true; + } else if (feature == null) { + log.warn("Feature {} not found", name); + } + } + return changed; + } + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/app/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/app/impl/package-info.java new file mode 100644 index 00000000..d5f30374 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/app/impl/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. + */ + +/** + * Subsystem for managing applications. + */ +package org.onosproject.app.impl; \ No newline at end of file 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 new file mode 100644 index 00000000..1933ee55 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ComponentConfigManager.java @@ -0,0 +1,281 @@ +/* + * 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.collect.Maps; +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.AbstractAccumulator; +import org.onlab.util.Accumulator; +import org.onlab.util.SharedExecutors; +import org.onosproject.cfg.ComponentConfigEvent; +import org.onosproject.cfg.ComponentConfigService; +import org.onosproject.cfg.ComponentConfigStore; +import org.onosproject.cfg.ComponentConfigStoreDelegate; +import org.onosproject.cfg.ConfigProperty; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; +import org.slf4j.Logger; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkArgument; +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.*; + + +/** + * Implementation of the centralized component configuration service. + */ +@Component(immediate = true) +@Service +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"; + + //Symbolic constants for use with the accumulator + private static final int MAX_ITEMS = 100; + private static final int MAX_BATCH_MILLIS = 1000; + private static final int MAX_IDLE_MILLIS = 250; + + private static final String RESOURCE_EXT = ".cfgdef"; + + private final Logger log = getLogger(getClass()); + + private final ComponentConfigStoreDelegate delegate = new InternalStoreDelegate(); + private final InternalAccumulator accumulator = new InternalAccumulator(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ComponentConfigStore store; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ConfigurationAdmin cfgAdmin; + + // Locally maintained catalog of definitions. + private final Map> properties = + Maps.newConcurrentMap(); + + + @Activate + public void activate() { + store.setDelegate(delegate); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + store.unsetDelegate(delegate); + log.info("Stopped"); + } + + @Override + public Set getComponentNames() { + checkPermission(CONFIG_READ); + + return ImmutableSet.copyOf(properties.keySet()); + } + + @Override + public void registerProperties(Class componentClass) { + checkPermission(CONFIG_WRITE); + + String componentName = componentClass.getName(); + String resourceName = componentClass.getSimpleName() + RESOURCE_EXT; + try (InputStream ris = componentClass.getResourceAsStream(resourceName)) { + checkArgument(ris != null, "Property definitions not found at resource %s", + resourceName); + + // Read the definitions + Set defs = ConfigPropertyDefinitions.read(ris); + + // Produce a new map of the properties and register it. + Map map = Maps.newConcurrentMap(); + defs.forEach(p -> map.put(p.name(), p)); + + properties.put(componentName, map); + loadExistingValues(componentName); + } catch (IOException e) { + log.error("Unable to read property definitions from resource " + resourceName, e); + } + } + + @Override + public void unregisterProperties(Class componentClass, boolean clear) { + checkPermission(CONFIG_WRITE); + + String componentName = componentClass.getName(); + checkNotNull(componentName, COMPONENT_NULL); + Map cps = properties.remove(componentName); + if (clear && cps != null) { + cps.keySet().forEach(name -> store.unsetProperty(componentName, name)); + clearExistingValues(componentName); + } + } + + // Clears any existing values that may have been set. + private void clearExistingValues(String componentName) { + triggerUpdate(componentName); + } + + @Override + public Set getProperties(String componentName) { + checkPermission(CONFIG_READ); + + Map map = properties.get(componentName); + return map != null ? ImmutableSet.copyOf(map.values()) : null; + } + + @Override + public void setProperty(String componentName, String name, String value) { + checkPermission(CONFIG_WRITE); + + checkNotNull(componentName, COMPONENT_NULL); + checkNotNull(name, PROPERTY_NULL); + store.setProperty(componentName, name, value); + } + + @Override + public void unsetProperty(String componentName, String name) { + checkPermission(CONFIG_WRITE); + + checkNotNull(componentName, COMPONENT_NULL); + checkNotNull(name, PROPERTY_NULL); + store.unsetProperty(componentName, name); + } + + private class InternalStoreDelegate implements ComponentConfigStoreDelegate { + + @Override + public void notify(ComponentConfigEvent event) { + String componentName = event.subject(); + String name = event.name(); + String value = event.value(); + + switch (event.type()) { + case PROPERTY_SET: + set(componentName, name, value); + break; + case PROPERTY_UNSET: + reset(componentName, name); + break; + default: + break; + } + } + } + + // Buffers multiple subsequent configuration updates into one notification. + private class InternalAccumulator extends AbstractAccumulator + implements Accumulator { + + protected InternalAccumulator() { + super(SharedExecutors.getTimer(), MAX_ITEMS, MAX_BATCH_MILLIS, MAX_IDLE_MILLIS); + } + + @Override + public void processItems(List items) { + // Conversion to set removes duplicates + Set componentSet = new HashSet<>(items); + componentSet.forEach(ComponentConfigManager.this::triggerUpdate); + } + } + + // Locates the property in the component map and replaces it with an + // updated copy. + private void set(String componentName, String name, String value) { + Map map = properties.get(componentName); + if (map != null) { + ConfigProperty prop = map.get(name); + if (prop != null) { + map.put(name, ConfigProperty.setProperty(prop, value)); + accumulator.add(componentName); + return; + } + } + log.warn("Unable to set non-existent property {} for component {}", + name, componentName); + } + + // Locates the property in the component map and replaces it with an + // reset copy. + private void reset(String componentName, String name) { + Map map = properties.get(componentName); + if (map != null) { + ConfigProperty prop = map.get(name); + if (prop != null) { + map.put(name, ConfigProperty.resetProperty(prop)); + accumulator.add(componentName); + return; + } + log.warn("Unable to reset non-existent property {} for component {}", + name, componentName); + } + } + + // Loads existing property values that may have been set. + private void loadExistingValues(String componentName) { + try { + Configuration cfg = cfgAdmin.getConfiguration(componentName, null); + Map map = properties.get(componentName); + Dictionary props = cfg.getProperties(); + if (props != null) { + Enumeration it = props.keys(); + while (it.hasMoreElements()) { + String name = it.nextElement(); + ConfigProperty p = map.get(name); + if (p != null) { + map.put(name, ConfigProperty.setProperty(p, (String) props.get(name))); + } + } + } + } catch (IOException e) { + log.error("Unable to get configuration for " + componentName, e); + } + + } + + // FIXME: This should be a slightly deferred execution to allow changing + // values just once per component when a number of updates arrive shortly + // after each other. + private void triggerUpdate(String componentName) { + try { + Configuration cfg = cfgAdmin.getConfiguration(componentName, null); + Map map = properties.get(componentName); + Dictionary props = new Hashtable<>(); + map.values().forEach(p -> props.put(p.name(), p.value())); + cfg.update(props); + } catch (IOException e) { + log.warn("Unable to update configuration for " + componentName, e); + } + } + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ConfigPropertyDefinitions.java b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ConfigPropertyDefinitions.java new file mode 100644 index 00000000..0f416c76 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/ConfigPropertyDefinitions.java @@ -0,0 +1,81 @@ +/* + * 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 org.onosproject.cfg.ConfigProperty; +import org.onosproject.cfg.ConfigProperty.Type; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.util.Set; + +import static org.onosproject.cfg.ConfigProperty.defineProperty; + +/** + * Utility for writing and reading configuration property definition file. + */ +public final class ConfigPropertyDefinitions { + + private static final String FMT = "%s|%s|%s|%s\n"; + private static final String SEP = "\\|"; + private static final String COMMENT = "#"; + + private ConfigPropertyDefinitions() { + } + + /** + * Writes the specified set of property definitions into the given output + * stream. + * + * @param stream output stream + * @param props properties whose definitions are to be written + * @throws java.io.IOException if unable to write the stream + */ + public static void write(OutputStream stream, Set props) throws IOException { + try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(stream))) { + props.forEach(p -> pw.format(FMT, p.name(), p.type(), p.description(), p.defaultValue())); + } + } + + /** + * Reads the specified input stream and creates from its contents a + * set of property definitions. + * + * @param stream input stream + * @return properties whose definitions are contained in the stream + * @throws java.io.IOException if unable to read the stream + */ + public static Set read(InputStream stream) throws IOException { + ImmutableSet.Builder builder = ImmutableSet.builder(); + try (BufferedReader br = new BufferedReader(new InputStreamReader(stream))) { + String line; + while ((line = br.readLine()) != null) { + if (!line.isEmpty() && !line.startsWith(COMMENT)) { + String[] f = line.split(SEP, 4); + builder.add(defineProperty(f[0], Type.valueOf(f[1]), f[2], f[3])); + } + } + } + return builder.build(); + } + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/package-info.java new file mode 100644 index 00000000..4f76c31c --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/cfg/impl/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. + */ + +/** + * Subsystem for central management of component configurations. + */ +package org.onosproject.cfg.impl; \ No newline at end of file diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterManager.java new file mode 100644 index 00000000..04d1dfdf --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/ClusterManager.java @@ -0,0 +1,156 @@ +/* + * Copyright 2014-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.cluster.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.apache.karaf.system.SystemService; +import org.joda.time.DateTime; +import org.onlab.packet.IpAddress; +import org.onosproject.cluster.ClusterAdminService; +import org.onosproject.cluster.ClusterDefinitionService; +import org.onosproject.cluster.ClusterEvent; +import org.onosproject.cluster.ClusterEventListener; +import org.onosproject.cluster.ClusterService; +import org.onosproject.cluster.ClusterStore; +import org.onosproject.cluster.ClusterStoreDelegate; +import org.onosproject.cluster.ControllerNode; +import org.onosproject.cluster.NodeId; +import org.onosproject.event.AbstractListenerManager; +import org.slf4j.Logger; + +import java.util.Set; + +import static com.google.common.base.Preconditions.checkArgument; +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.*; + + + +/** + * Implementation of the cluster service. + */ +@Component(immediate = true) +@Service +public class ClusterManager + extends AbstractListenerManager + implements ClusterService, ClusterAdminService { + + public static final String INSTANCE_ID_NULL = "Instance ID cannot be null"; + private final Logger log = getLogger(getClass()); + + private ClusterStoreDelegate delegate = new InternalStoreDelegate(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterDefinitionService clusterDefinitionService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterStore store; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected SystemService systemService; + + @Activate + public void activate() { + store.setDelegate(delegate); + eventDispatcher.addSink(ClusterEvent.class, listenerRegistry); + clusterDefinitionService.seedNodes() + .forEach(node -> store.addNode(node.id(), node.ip(), node.tcpPort())); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + store.unsetDelegate(delegate); + eventDispatcher.removeSink(ClusterEvent.class); + log.info("Stopped"); + } + + @Override + public ControllerNode getLocalNode() { + checkPermission(CLUSTER_READ); + return store.getLocalNode(); + } + + @Override + public Set getNodes() { + checkPermission(CLUSTER_READ); + return store.getNodes(); + } + + @Override + public ControllerNode getNode(NodeId nodeId) { + checkPermission(CLUSTER_READ); + checkNotNull(nodeId, INSTANCE_ID_NULL); + return store.getNode(nodeId); + } + + @Override + public ControllerNode.State getState(NodeId nodeId) { + checkPermission(CLUSTER_READ); + checkNotNull(nodeId, INSTANCE_ID_NULL); + return store.getState(nodeId); + } + + + @Override + public DateTime getLastUpdated(NodeId nodeId) { + checkPermission(CLUSTER_READ); + return store.getLastUpdated(nodeId); + } + + @Override + public void formCluster(Set nodes, String ipPrefix) { + checkNotNull(nodes, "Nodes cannot be null"); + checkArgument(!nodes.isEmpty(), "Nodes cannot be empty"); + checkNotNull(ipPrefix, "IP prefix cannot be null"); + clusterDefinitionService.formCluster(nodes, ipPrefix); + try { + log.warn("Shutting down container for cluster reconfiguration!"); + systemService.reboot("now", SystemService.Swipe.NONE); + } catch (Exception e) { + log.error("Unable to reboot container", e); + } + } + + @Override + public ControllerNode addNode(NodeId nodeId, IpAddress ip, int tcpPort) { + checkNotNull(nodeId, INSTANCE_ID_NULL); + checkNotNull(ip, "IP address cannot be null"); + checkArgument(tcpPort > 5000, "TCP port must be > 5000"); + return store.addNode(nodeId, ip, tcpPort); + } + + @Override + public void removeNode(NodeId nodeId) { + checkNotNull(nodeId, INSTANCE_ID_NULL); + store.removeNode(nodeId); + } + + // Store delegate to re-post events emitted from the store. + private class InternalStoreDelegate implements ClusterStoreDelegate { + @Override + public void notify(ClusterEvent event) { + post(event); + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/MastershipManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/MastershipManager.java new file mode 100644 index 00000000..56d369fd --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/MastershipManager.java @@ -0,0 +1,282 @@ +/* + * Copyright 2014-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.cluster.impl; + +import com.codahale.metrics.Timer; +import com.codahale.metrics.Timer.Context; +import com.google.common.collect.Lists; +import com.google.common.util.concurrent.Futures; +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.metrics.MetricsService; +import org.onosproject.cluster.ClusterService; +import org.onosproject.cluster.ControllerNode; +import org.onosproject.cluster.NodeId; +import org.onosproject.cluster.RoleInfo; +import org.onosproject.event.AbstractListenerManager; +import org.onosproject.core.MetricsHelper; +import org.onosproject.mastership.MastershipAdminService; +import org.onosproject.mastership.MastershipEvent; +import org.onosproject.mastership.MastershipListener; +import org.onosproject.mastership.MastershipService; +import org.onosproject.mastership.MastershipStore; +import org.onosproject.mastership.MastershipStoreDelegate; +import org.onosproject.mastership.MastershipTerm; +import org.onosproject.mastership.MastershipTermService; +import org.onosproject.net.DeviceId; +import org.onosproject.net.MastershipRole; +import org.slf4j.Logger; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Lists.newArrayList; +import static org.onlab.metrics.MetricsUtil.startTimer; +import static org.onlab.metrics.MetricsUtil.stopTimer; +import static org.onosproject.cluster.ControllerNode.State.ACTIVE; +import static org.onosproject.net.MastershipRole.MASTER; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.slf4j.LoggerFactory.getLogger; +import static org.onosproject.security.AppPermission.Type.*; + + + +@Component(immediate = true) +@Service +public class MastershipManager + extends AbstractListenerManager + implements MastershipService, MastershipAdminService, MastershipTermService, + MetricsHelper { + + private static final String NODE_ID_NULL = "Node ID cannot be null"; + private static final String DEVICE_ID_NULL = "Device ID cannot be null"; + private static final String ROLE_NULL = "Mastership role cannot be null"; + + private final Logger log = getLogger(getClass()); + + private final MastershipStoreDelegate delegate = new InternalDelegate(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected MastershipStore store; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterService clusterService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected MetricsService metricsService; + + private NodeId localNodeId; + private Timer requestRoleTimer; + + @Activate + public void activate() { + requestRoleTimer = createTimer("Mastership", "requestRole", "responseTime"); + localNodeId = clusterService.getLocalNode().id(); + eventDispatcher.addSink(MastershipEvent.class, listenerRegistry); + store.setDelegate(delegate); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + eventDispatcher.removeSink(MastershipEvent.class); + store.unsetDelegate(delegate); + log.info("Stopped"); + } + + @Override + public CompletableFuture setRole(NodeId nodeId, DeviceId deviceId, MastershipRole role) { + checkNotNull(nodeId, NODE_ID_NULL); + checkNotNull(deviceId, DEVICE_ID_NULL); + checkNotNull(role, ROLE_NULL); + + CompletableFuture eventFuture = null; + + switch (role) { + case MASTER: + eventFuture = store.setMaster(nodeId, deviceId); + break; + case STANDBY: + eventFuture = store.setStandby(nodeId, deviceId); + break; + case NONE: + eventFuture = store.relinquishRole(nodeId, deviceId); + break; + default: + log.info("Unknown role; ignoring"); + return CompletableFuture.completedFuture(null); + } + + return eventFuture.thenAccept(this::post) + .thenApply(v -> null); + } + + @Override + public MastershipRole getLocalRole(DeviceId deviceId) { + checkPermission(CLUSTER_READ); + + checkNotNull(deviceId, DEVICE_ID_NULL); + return store.getRole(clusterService.getLocalNode().id(), deviceId); + } + + @Override + public CompletableFuture relinquishMastership(DeviceId deviceId) { + checkPermission(CLUSTER_WRITE); + return store.relinquishRole(localNodeId, deviceId) + .thenAccept(this::post) + .thenApply(v -> null); + } + + @Override + public CompletableFuture requestRoleFor(DeviceId deviceId) { + checkPermission(CLUSTER_WRITE); + + checkNotNull(deviceId, DEVICE_ID_NULL); + final Context timer = startTimer(requestRoleTimer); + return store.requestRole(deviceId).whenComplete((result, error) -> stopTimer(timer)); + + } + + @Override + public NodeId getMasterFor(DeviceId deviceId) { + checkPermission(CLUSTER_READ); + + checkNotNull(deviceId, DEVICE_ID_NULL); + return store.getMaster(deviceId); + } + + @Override + public Set getDevicesOf(NodeId nodeId) { + checkPermission(CLUSTER_READ); + + checkNotNull(nodeId, NODE_ID_NULL); + return store.getDevices(nodeId); + } + + @Override + public RoleInfo getNodesFor(DeviceId deviceId) { + checkPermission(CLUSTER_READ); + + checkNotNull(deviceId, DEVICE_ID_NULL); + return store.getNodes(deviceId); + } + + @Override + public MastershipTerm getMastershipTerm(DeviceId deviceId) { + return store.getTermFor(deviceId); + } + + @Override + public MetricsService metricsService() { + return metricsService; + } + + @Override + public void balanceRoles() { + List nodes = newArrayList(clusterService.getNodes()); + Map> controllerDevices = new HashMap<>(); + int deviceCount = 0; + + // Create buckets reflecting current ownership. + for (ControllerNode node : nodes) { + if (clusterService.getState(node.id()) == ACTIVE) { + Set devicesOf = new HashSet<>(getDevicesOf(node.id())); + deviceCount += devicesOf.size(); + controllerDevices.put(node, devicesOf); + log.info("Node {} has {} devices.", node.id(), devicesOf.size()); + } + } + + // Now re-balance the buckets until they are roughly even. + List> balanceBucketsFutures = Lists.newLinkedList(); + int rounds = controllerDevices.keySet().size(); + for (int i = 0; i < rounds; i++) { + // Iterate over the buckets and find the smallest and the largest. + ControllerNode smallest = findBucket(true, controllerDevices); + ControllerNode largest = findBucket(false, controllerDevices); + balanceBucketsFutures.add(balanceBuckets(smallest, largest, controllerDevices, deviceCount)); + } + CompletableFuture balanceRolesFuture = CompletableFuture.allOf( + balanceBucketsFutures.toArray(new CompletableFuture[balanceBucketsFutures.size()])); + + Futures.getUnchecked(balanceRolesFuture); + } + + private ControllerNode findBucket(boolean min, + Map> controllerDevices) { + int xSize = min ? Integer.MAX_VALUE : -1; + ControllerNode xNode = null; + for (ControllerNode node : controllerDevices.keySet()) { + int size = controllerDevices.get(node).size(); + if ((min && size < xSize) || (!min && size > xSize)) { + xSize = size; + xNode = node; + } + } + return xNode; + } + + private CompletableFuture balanceBuckets(ControllerNode smallest, ControllerNode largest, + Map> controllerDevices, + int deviceCount) { + Collection minBucket = controllerDevices.get(smallest); + Collection maxBucket = controllerDevices.get(largest); + int bucketCount = controllerDevices.keySet().size(); + + int delta = (maxBucket.size() - minBucket.size()) / 2; + delta = Math.min(deviceCount / bucketCount, delta); + + List> setRoleFutures = Lists.newLinkedList(); + + if (delta > 0) { + log.info("Attempting to move {} nodes from {} to {}...", delta, + largest.id(), smallest.id()); + + int i = 0; + Iterator it = maxBucket.iterator(); + while (it.hasNext() && i < delta) { + DeviceId deviceId = it.next(); + log.info("Setting {} as the master for {}", smallest.id(), deviceId); + setRoleFutures.add(setRole(smallest.id(), deviceId, MASTER)); + controllerDevices.get(smallest).add(deviceId); + it.remove(); + i++; + } + } + + return CompletableFuture.allOf(setRoleFutures.toArray(new CompletableFuture[setRoleFutures.size()])); + } + + + public class InternalDelegate implements MastershipStoreDelegate { + @Override + public void notify(MastershipEvent event) { + post(event); + } + } + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/package-info.java new file mode 100644 index 00000000..653edaa5 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/cluster/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Subsystem for tracking controller cluster nodes. + */ +package org.onosproject.cluster.impl; diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/BlockAllocatorBasedIdGenerator.java b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/BlockAllocatorBasedIdGenerator.java new file mode 100644 index 00000000..267cd713 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/BlockAllocatorBasedIdGenerator.java @@ -0,0 +1,65 @@ +/* + * Copyright 2014 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.core.impl; + +import java.util.concurrent.atomic.AtomicBoolean; + +import org.onosproject.core.IdBlock; +import org.onosproject.core.IdGenerator; +import org.onosproject.core.UnavailableIdException; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Base class of {@link IdGenerator} implementations which use {@link IdBlockAllocator} as + * backend. + */ +public class BlockAllocatorBasedIdGenerator implements IdGenerator { + protected final IdBlockAllocator allocator; + protected IdBlock idBlock; + protected AtomicBoolean initialized; + + + /** + * Constructs an ID generator which use {@link IdBlockAllocator} as backend. + * + * @param allocator the ID block allocator to use + */ + protected BlockAllocatorBasedIdGenerator(IdBlockAllocator allocator) { + this.allocator = checkNotNull(allocator, "allocator cannot be null"); + this.initialized = new AtomicBoolean(false); + } + + @Override + public long getNewId() { + try { + if (!initialized.get()) { + synchronized (allocator) { + if (!initialized.get()) { + idBlock = allocator.allocateUniqueIdBlock(); + initialized.set(true); + } + } + } + return idBlock.getNextId(); + } catch (UnavailableIdException e) { + synchronized (allocator) { + idBlock = allocator.allocateUniqueIdBlock(); + } + return idBlock.getNextId(); + } + } +} 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 new file mode 100644 index 00000000..07612292 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/CoreManager.java @@ -0,0 +1,190 @@ +/* + * Copyright 2014-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.core.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.Modified; +import org.apache.felix.scr.annotations.Property; +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; +import org.onosproject.core.CoreService; +import org.onosproject.core.IdBlockStore; +import org.onosproject.core.IdGenerator; +import org.onosproject.core.Version; +import org.onosproject.event.EventDeliveryService; +import org.osgi.service.component.ComponentContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.Dictionary; +import java.util.List; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Strings.isNullOrEmpty; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.onosproject.security.AppPermission.Type.*; + + + +/** + * Core service implementation. + */ +@Component(immediate = true) +@Service +public class CoreManager implements CoreService { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private static final File VERSION_FILE = new File("../VERSION"); + private static Version version = Version.version("1.3.0-SNAPSHOT"); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ApplicationIdStore applicationIdStore; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IdBlockStore idBlockStore; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ComponentConfigService cfgService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected EventDeliveryService eventDeliveryService; + + private static final int DEFAULT_POOL_SIZE = 30; + @Property(name = "sharedThreadPoolSize", intValue = DEFAULT_POOL_SIZE, + label = "Configure shared pool maximum size ") + private int sharedThreadPoolSize = DEFAULT_POOL_SIZE; + + private static final int DEFAULT_EVENT_TIME = 2000; + @Property(name = "maxEventTimeLimit", intValue = DEFAULT_EVENT_TIME, + label = "Maximum number of millis an event sink has to process an event") + private int maxEventTimeLimit = DEFAULT_EVENT_TIME; + + @Activate + 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)); + } + } + + @Deactivate + public void deactivate() { + cfgService.unregisterProperties(getClass(), false); + SharedExecutors.shutdown(); + } + + @Override + public Version version() { + checkPermission(APP_READ); + + return version; + } + + @Override + public Set getAppIds() { + checkPermission(APP_READ); + + return applicationIdStore.getAppIds(); + } + + @Override + public ApplicationId getAppId(Short id) { + checkPermission(APP_READ); + + return applicationIdStore.getAppId(id); + } + + @Override + public ApplicationId getAppId(String name) { + checkPermission(APP_READ); + + return applicationIdStore.getAppId(name); + } + + + @Override + public ApplicationId registerApplication(String name) { + checkNotNull(name, "Application ID cannot be null"); + return applicationIdStore.registerApplication(name); + } + + @Override + public IdGenerator getIdGenerator(String topic) { + IdBlockAllocator allocator = new StoreBasedIdBlockAllocator(topic, idBlockStore); + return new BlockAllocatorBasedIdGenerator(allocator); + } + + + @Modified + public void modified(ComponentContext context) { + Dictionary properties = context.getProperties(); + Integer poolSize = getIntegerProperty(properties, "sharedThreadPoolSize"); + + if (poolSize != null && poolSize > 1) { + sharedThreadPoolSize = poolSize; + SharedExecutors.setPoolSize(sharedThreadPoolSize); + } else if (poolSize != null) { + log.warn("sharedThreadPoolSize must be greater than 1"); + } + + Integer timeLimit = getIntegerProperty(properties, "maxEventTimeLimit"); + if (timeLimit != null && timeLimit > 1) { + maxEventTimeLimit = timeLimit; + eventDeliveryService.setDispatchTimeLimit(maxEventTimeLimit); + } else if (timeLimit != null) { + log.warn("maxEventTimeLimit must be greater than 1"); + } + + log.info("Settings: sharedThreadPoolSize={}, maxEventTimeLimit={}", + sharedThreadPoolSize, maxEventTimeLimit); + } + + + /** + * Get Integer property from the propertyName + * Return null if propertyName is not found. + * + * @param properties properties to be looked up + * @param propertyName the name of the property to look up + * @return value when the propertyName is defined or return null + */ + private static Integer getIntegerProperty(Dictionary properties, + String propertyName) { + Integer value = null; + try { + String s = (String) properties.get(propertyName); + value = isNullOrEmpty(s) ? value : Integer.parseInt(s.trim()); + } catch (NumberFormatException | ClassCastException e) { + value = null; + } + return value; + } + + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/IdBlockAllocator.java b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/IdBlockAllocator.java new file mode 100644 index 00000000..ba8594f2 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/IdBlockAllocator.java @@ -0,0 +1,38 @@ +/* + * Copyright 2014 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.core.impl; + +import org.onosproject.core.IdBlock; + +/** + * An interface that gives unique ID spaces. + */ +public interface IdBlockAllocator { + /** + * Allocates a unique Id Block. + * + * @return Id Block. + */ + IdBlock allocateUniqueIdBlock(); + + /** + * Allocates next unique id and retrieve a new range of ids if needed. + * + * @param range range to use for the identifier + * @return Id Block. + */ + IdBlock allocateUniqueIdBlock(long range); +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/MetricsManagerComponent.java b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/MetricsManagerComponent.java new file mode 100644 index 00000000..5a3f08df --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/MetricsManagerComponent.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014 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.core.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.Service; + +import org.onlab.metrics.MetricsManager; + +/** + * Metrics service implementation. + */ +@Component(immediate = true) +@Service +public class MetricsManagerComponent extends MetricsManager { + + @Activate + protected void activate() { + super.clear(); + } + + @Deactivate + protected void deactivate() { + super.clear(); + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/StoreBasedIdBlockAllocator.java b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/StoreBasedIdBlockAllocator.java new file mode 100644 index 00000000..c28de73d --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/StoreBasedIdBlockAllocator.java @@ -0,0 +1,46 @@ +/* + * Copyright 2014 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.core.impl; + +import org.onosproject.core.IdBlock; +import org.onosproject.core.IdBlockStore; + +public class StoreBasedIdBlockAllocator implements IdBlockAllocator { + private final IdBlockStore store; + private final String topic; + + public StoreBasedIdBlockAllocator(String topic, IdBlockStore store) { + this.topic = topic; + this.store = store; + } + + /** + * Returns a block of IDs which are unique and unused. + * Range of IDs is fixed size and is assigned incrementally as this method + * called. + * + * @return an IdBlock containing a set of unique IDs + */ + @Override + public synchronized IdBlock allocateUniqueIdBlock() { + return store.getIdBlock(topic); + } + + @Override + public IdBlock allocateUniqueIdBlock(long range) { + throw new UnsupportedOperationException("Not supported yet"); + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/package-info.java new file mode 100644 index 00000000..f8c3e672 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/core/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Miscellaneous core system implementations. + */ +package org.onosproject.core.impl; diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/event/impl/CoreEventDispatcher.java b/framework/src/onos/core/net/src/main/java/org/onosproject/event/impl/CoreEventDispatcher.java new file mode 100644 index 00000000..79ce74b7 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/event/impl/CoreEventDispatcher.java @@ -0,0 +1,175 @@ +/* + * Copyright 2014-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.event.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.Service; +import org.onlab.util.SharedExecutors; +import org.onosproject.event.AbstractEvent; +import org.onosproject.event.DefaultEventSinkRegistry; +import org.onosproject.event.Event; +import org.onosproject.event.EventDeliveryService; +import org.onosproject.event.EventSink; +import org.slf4j.Logger; + +import java.util.TimerTask; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.concurrent.Executors.newSingleThreadExecutor; +import static org.onlab.util.Tools.groupedThreads; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Simple implementation of an event dispatching service. + */ +@Component(immediate = true) +@Service +public class CoreEventDispatcher extends DefaultEventSinkRegistry + implements EventDeliveryService { + + private final Logger log = getLogger(getClass()); + + // Default number of millis a sink can take to process an event. + private static final long DEFAULT_EXECUTE_MS = 5_000; // ms + private static final long WATCHDOG_MS = 250; // ms + + private final BlockingQueue events = new LinkedBlockingQueue<>(); + + private final ExecutorService executor = + newSingleThreadExecutor(groupedThreads("onos/event", "dispatch-%d")); + + @SuppressWarnings("unchecked") + private static final Event KILL_PILL = new AbstractEvent(null, 0) { + }; + + private DispatchLoop dispatchLoop; + private long maxProcessMillis = DEFAULT_EXECUTE_MS; + + // Means to detect long-running sinks + private TimerTask watchdog; + private EventSink lastSink; + private long lastStart = 0; + private Future dispatchFuture; + + @Override + public void post(Event event) { + if (!events.add(event)) { + log.error("Unable to post event {}", event); + } + } + + @Activate + public void activate() { + dispatchLoop = new DispatchLoop(); + dispatchFuture = executor.submit(dispatchLoop); + watchdog = new Watchdog(); + SharedExecutors.getTimer().schedule(watchdog, WATCHDOG_MS, WATCHDOG_MS); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + dispatchLoop.stop(); + watchdog.cancel(); + post(KILL_PILL); + log.info("Stopped"); + } + + @Override + public void setDispatchTimeLimit(long millis) { + checkArgument(millis >= WATCHDOG_MS, + "Time limit must be greater than %s", WATCHDOG_MS); + maxProcessMillis = millis; + } + + @Override + public long getDispatchTimeLimit() { + return maxProcessMillis; + } + + // Auxiliary event dispatching loop that feeds off the events queue. + private class DispatchLoop implements Runnable { + private volatile boolean stopped; + + @Override + public void run() { + stopped = false; + log.info("Dispatch loop initiated"); + while (!stopped) { + try { + // Fetch the next event and if it is the kill-pill, bail + Event event = events.take(); + if (event == KILL_PILL) { + break; + } + process(event); + } catch (InterruptedException e) { + log.warn("Dispatch loop interrupted"); + } catch (Exception e) { + log.warn("Error encountered while dispatching event:", e); + } + } + log.info("Dispatch loop terminated"); + } + + // Locate the sink for the event class and use it to process the event + @SuppressWarnings("unchecked") + private void process(Event event) { + EventSink sink = getSink(event.getClass()); + if (sink != null) { + lastSink = sink; + lastStart = System.currentTimeMillis(); + sink.process(event); + lastStart = 0; + } else { + log.warn("No sink registered for event class {}", + event.getClass().getName()); + } + } + + void stop() { + stopped = true; + } + } + + // Monitors event sinks to make sure none take too long to execute. + private class Watchdog extends TimerTask { + @Override + public void run() { + long delta = System.currentTimeMillis() - lastStart; + if (lastStart > 0 && delta > maxProcessMillis) { + lastStart = 0; + log.warn("Event sink {} exceeded execution time limit: {} ms; spawning new dispatch loop", + lastSink.getClass().getName(), delta); + + // Notify the sink that it has exceeded its time limit. + lastSink.onProcessLimit(); + + // Cancel the old dispatch loop and submit a new one. + dispatchLoop.stop(); + dispatchLoop = new DispatchLoop(); + dispatchFuture.cancel(true); + dispatchFuture = executor.submit(dispatchLoop); + } + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/event/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/event/impl/package-info.java new file mode 100644 index 00000000..f0882f3d --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/event/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Local event dispatching mechanism. + */ +package org.onosproject.event.impl; diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/BasicNetworkConfigs.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/BasicNetworkConfigs.java new file mode 100644 index 00000000..de2f5c3b --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/BasicNetworkConfigs.java @@ -0,0 +1,115 @@ +/* + * 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.config.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; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onosproject.core.CoreService; +import org.onosproject.incubator.net.config.basics.InterfaceConfig; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.HostId; +import org.onosproject.net.LinkKey; +import org.onosproject.net.config.ConfigFactory; +import org.onosproject.net.config.NetworkConfigRegistry; +import org.onosproject.net.config.basics.BasicDeviceConfig; +import org.onosproject.net.config.basics.BasicHostConfig; +import org.onosproject.net.config.basics.BasicLinkConfig; +import org.onosproject.net.config.basics.OpticalPortConfig; +import org.onosproject.net.config.basics.SubjectFactories; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Set; + +import static org.onosproject.net.config.basics.SubjectFactories.*; + +/** + * Component for registration of builtin basic network configurations. + */ +@Component(immediate = true) +public class BasicNetworkConfigs { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private final Set factories = ImmutableSet.of( + new ConfigFactory(DEVICE_SUBJECT_FACTORY, + BasicDeviceConfig.class, + "basic") { + @Override + public BasicDeviceConfig createConfig() { + return new BasicDeviceConfig(); + } + }, + new ConfigFactory(CONNECT_POINT_SUBJECT_FACTORY, + InterfaceConfig.class, + "interfaces", + true) { + @Override + public InterfaceConfig createConfig() { + return new InterfaceConfig(); + } + }, + new ConfigFactory(HOST_SUBJECT_FACTORY, + BasicHostConfig.class, + "basic") { + @Override + public BasicHostConfig createConfig() { + return new BasicHostConfig(); + } + }, + new ConfigFactory(LINK_SUBJECT_FACTORY, + BasicLinkConfig.class, + "basic") { + @Override + public BasicLinkConfig createConfig() { + return new BasicLinkConfig(); + } + }, + new ConfigFactory(CONNECT_POINT_SUBJECT_FACTORY, + OpticalPortConfig.class, + "optical") { + @Override + public OpticalPortConfig createConfig() { + return new OpticalPortConfig(); + } + } + ); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected NetworkConfigRegistry registry; + + @Activate + public void activate() { + SubjectFactories.setCoreService(coreService); + factories.forEach(registry::registerConfigFactory); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + factories.forEach(registry::unregisterConfigFactory); + log.info("Stopped"); + } + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigLoader.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigLoader.java new file mode 100644 index 00000000..01348c15 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigLoader.java @@ -0,0 +1,218 @@ +/* + * 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.config.impl; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.Maps; +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.onosproject.net.config.Config; +import org.onosproject.net.config.NetworkConfigEvent; +import org.onosproject.net.config.NetworkConfigListener; +import org.onosproject.net.config.NetworkConfigService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; + +/** + * Component for loading the initial network configuration. + */ +@Component(immediate = true) +public class NetworkConfigLoader { + + private static final File CFG_FILE = new File("../config/network-cfg.json"); + + private final Logger log = LoggerFactory.getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected NetworkConfigService networkConfigService; + + // FIXME: Add mutual exclusion to make sure this happens only once per startup. + + private final Map jsons = Maps.newConcurrentMap(); + + private final NetworkConfigListener configListener = new InnerConfigListener(); + + private ObjectNode root; + + @Activate + public void activate() { + //TODO Maybe this should be at the bottom to avoid a potential race + networkConfigService.addListener(configListener); + try { + if (CFG_FILE.exists()) { + root = (ObjectNode) new ObjectMapper().readTree(CFG_FILE); + + populateConfigurations(); + + applyConfigurations(); + + log.info("Loaded initial network configuration from {}", CFG_FILE); + } + } catch (Exception e) { + log.warn("Unable to load initial network configuration from {}", + CFG_FILE, e); + } + } + + @Deactivate + public void deactivate() { + networkConfigService.removeListener(configListener); + } + // sweep through pending config jsons and try to add them + + /** + * Inner class that allows for handling of newly added NetConfig types. + */ + private final class InnerConfigListener implements NetworkConfigListener { + + @Override + public void event(NetworkConfigEvent event) { + //TODO should this be done for other types of NetworkConfigEvents? + if (event.type() == NetworkConfigEvent.Type.CONFIG_REGISTERED || + event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) { + applyConfigurations(); + } + + } + } + + /** + * Inner class that allows for tracking of JSON class configurations. + */ + private final class InnerConfigPosition { + private final String subjectKey, subject, configKey; + + private String subjectKey() { + return subjectKey; + } + + private String subject() { + return subject; + } + + private String configKey() { + return configKey; + } + + private InnerConfigPosition(String subjectKey, String subject, String configKey) { + this.subjectKey = subjectKey; + this.subject = subject; + this.configKey = configKey; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof InnerConfigPosition) { + final InnerConfigPosition that = (InnerConfigPosition) obj; + return Objects.equals(this.subjectKey, that.subjectKey) + && Objects.equals(this.subject, that.subject) + && Objects.equals(this.configKey, that.configKey); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(subjectKey, subject, configKey); + } + } + + /** + * Save the JSON leaves associated with a specific subject key. + * + * @param sk the subject key string. + * @param node the node associated with the subject key. + */ + private void saveJson(String sk, ObjectNode node) { + node.fieldNames().forEachRemaining(s -> + saveSubjectJson(sk, s, (ObjectNode) node.path(s))); + } + + /** + * Save the JSON leaves of the tree rooted as the node 'node' with subject key 'sk'. + * + * @param sk the string of the subject key. + * @param s the subject name. + * @param node the node rooting this subtree. + */ + private void saveSubjectJson(String sk, + String s, ObjectNode node) { + node.fieldNames().forEachRemaining(c -> + this.jsons.put(new InnerConfigPosition(sk, s, c), node.path(c))); + } + + /** + * Iterate through the JSON and populate a list of the leaf nodes of the structure. + */ + private void populateConfigurations() { + root.fieldNames().forEachRemaining(sk -> + saveJson(sk, (ObjectNode) root.path(sk))); + + } + + /** + * Apply the configurations associated with all of the config classes that + * are imported and have not yet been applied. + */ + private void applyConfigurations() { + Iterator> iter = jsons.entrySet().iterator(); + + Map.Entry entry; + InnerConfigPosition key; + JsonNode node; + String subjectKey; + String subjectString; + String configKey; + + while (iter.hasNext()) { + entry = iter.next(); + node = entry.getValue(); + key = entry.getKey(); + subjectKey = key.subjectKey(); + subjectString = key.subject(); + configKey = key.configKey(); + + Class configClass = + networkConfigService.getConfigClass(subjectKey, configKey); + //Check that the config class has been imported + if (configClass != null) { + + Object subject = networkConfigService.getSubjectFactory(subjectKey). + createSubject(subjectString); + + //Apply the configuration + networkConfigService.applyConfig(subject, configClass, node); + + //Now that it has been applied the corresponding JSON entry is no longer needed + iter.remove(); + } + } + } + +} 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 new file mode 100644 index 00000000..5cd96cab --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/NetworkConfigManager.java @@ -0,0 +1,288 @@ +/* + * 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.config.impl; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +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.event.AbstractListenerManager; +import org.onosproject.net.config.Config; +import org.onosproject.net.config.ConfigFactory; +import org.onosproject.net.config.NetworkConfigEvent; +import org.onosproject.net.config.NetworkConfigListener; +import org.onosproject.net.config.NetworkConfigRegistry; +import org.onosproject.net.config.NetworkConfigService; +import org.onosproject.net.config.NetworkConfigStore; +import org.onosproject.net.config.NetworkConfigStoreDelegate; +import org.onosproject.net.config.SubjectFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Implementation of the network configuration subsystem. + */ +@Component(immediate = true) +@Service +public class NetworkConfigManager + extends AbstractListenerManager + implements NetworkConfigRegistry, NetworkConfigService { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private static final String NULL_FACTORY_MSG = "Factory cannot be null"; + private static final String NULL_SCLASS_MSG = "Subject class cannot be null"; + private static final String NULL_CCLASS_MSG = "Config class cannot be null"; + private static final String NULL_SUBJECT_MSG = "Subject cannot be null"; + + // Inventory of configuration factories + private final Map factories = Maps.newConcurrentMap(); + + // Secondary indices to retrieve subject and config classes by keys + private final Map subjectClasses = Maps.newConcurrentMap(); + private final Map subjectClassKeys = Maps.newConcurrentMap(); + private final Map> configClasses = Maps.newConcurrentMap(); + + private final NetworkConfigStoreDelegate storeDelegate = new InternalStoreDelegate(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected NetworkConfigStore store; + + + @Activate + public void activate() { + eventDispatcher.addSink(NetworkConfigEvent.class, listenerRegistry); + store.setDelegate(storeDelegate); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + eventDispatcher.removeSink(NetworkConfigEvent.class); + store.unsetDelegate(storeDelegate); + log.info("Stopped"); + } + + + @Override + @SuppressWarnings("unchecked") + public void registerConfigFactory(ConfigFactory configFactory) { + checkNotNull(configFactory, NULL_FACTORY_MSG); + factories.put(key(configFactory), configFactory); + configClasses.put(identifier(configFactory), configFactory.configClass()); + + SubjectFactory subjectFactory = configFactory.subjectFactory(); + subjectClasses.putIfAbsent(subjectFactory.subjectKey(), subjectFactory); + subjectClassKeys.putIfAbsent(subjectFactory.subjectClass(), subjectFactory); + + store.addConfigFactory(configFactory); + } + + @Override + public void unregisterConfigFactory(ConfigFactory configFactory) { + checkNotNull(configFactory, NULL_FACTORY_MSG); + factories.remove(key(configFactory)); + configClasses.remove(identifier(configFactory)); + + // Note that we are deliberately not removing subject factory key bindings. + store.removeConfigFactory(configFactory); + } + + @Override + public Set getConfigFactories() { + return ImmutableSet.copyOf(factories.values()); + } + + + @Override + @SuppressWarnings("unchecked") + public > Set> getConfigFactories(Class subjectClass) { + ImmutableSet.Builder> builder = ImmutableSet.builder(); + factories.forEach((key, factory) -> { + if (factory.subjectFactory().subjectClass().equals(subjectClass)) { + builder.add(factory); + } + }); + return builder.build(); + } + + @Override + public > ConfigFactory getConfigFactory(Class configClass) { + checkNotNull(configClass, NULL_CCLASS_MSG); + return store.getConfigFactory(configClass); + } + + + @Override + public Set getSubjectClasses() { + ImmutableSet.Builder builder = ImmutableSet.builder(); + factories.forEach((k, v) -> builder.add(k.subjectClass)); + return builder.build(); + } + + @Override + public SubjectFactory getSubjectFactory(String subjectKey) { + return subjectClasses.get(subjectKey); + } + + @Override + public SubjectFactory getSubjectFactory(Class subjectClass) { + return subjectClassKeys.get(subjectClass); + } + + @Override + public Class getConfigClass(String subjectKey, String configKey) { + return configClasses.get(new ConfigIdentifier(subjectKey, configKey)); + } + + @Override + public Set getSubjects(Class subjectClass) { + checkNotNull(subjectClass, NULL_SCLASS_MSG); + return store.getSubjects(subjectClass); + } + + @Override + public > Set getSubjects(Class subjectClass, Class configClass) { + checkNotNull(subjectClass, NULL_SCLASS_MSG); + checkNotNull(configClass, NULL_CCLASS_MSG); + return store.getSubjects(subjectClass, configClass); + } + + @Override + public Set> getConfigs(S subject) { + checkNotNull(subject, NULL_SUBJECT_MSG); + Set>> configClasses = store.getConfigClasses(subject); + ImmutableSet.Builder> cfg = ImmutableSet.builder(); + configClasses.forEach(cc -> cfg.add(store.getConfig(subject, cc))); + return cfg.build(); + } + + @Override + public > T getConfig(S subject, Class configClass) { + checkNotNull(subject, NULL_SUBJECT_MSG); + checkNotNull(configClass, NULL_CCLASS_MSG); + return store.getConfig(subject, configClass); + } + + + @Override + public > C addConfig(S subject, Class configClass) { + checkNotNull(subject, NULL_SUBJECT_MSG); + checkNotNull(configClass, NULL_CCLASS_MSG); + return store.createConfig(subject, configClass); + } + + @Override + public > C applyConfig(S subject, Class configClass, JsonNode json) { + checkNotNull(subject, NULL_SUBJECT_MSG); + checkNotNull(configClass, NULL_CCLASS_MSG); + return store.applyConfig(subject, configClass, json); + } + + @Override + public > void removeConfig(S subject, Class configClass) { + checkNotNull(subject, NULL_SUBJECT_MSG); + checkNotNull(configClass, NULL_CCLASS_MSG); + store.clearConfig(subject, configClass); + } + + // Auxiliary store delegate to receive notification about changes in + // the network configuration store state - by the store itself. + private class InternalStoreDelegate implements NetworkConfigStoreDelegate { + @Override + public void notify(NetworkConfigEvent event) { + post(event); + } + } + + + // Produces a key for uniquely tracking a config factory. + private static ConfigKey key(ConfigFactory factory) { + return new ConfigKey(factory.subjectFactory().subjectClass(), factory.configClass()); + } + + // Auxiliary key to track config factories. + protected static final class ConfigKey { + final Class subjectClass; + final Class configClass; + + protected ConfigKey(Class subjectClass, Class configClass) { + this.subjectClass = subjectClass; + this.configClass = configClass; + } + + @Override + public int hashCode() { + return Objects.hash(subjectClass, configClass); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ConfigKey) { + final ConfigKey other = (ConfigKey) obj; + return Objects.equals(this.subjectClass, other.subjectClass) + && Objects.equals(this.configClass, other.configClass); + } + return false; + } + } + + private static ConfigIdentifier identifier(ConfigFactory factory) { + return new ConfigIdentifier(factory.subjectFactory().subjectKey(), factory.configKey()); + } + + static final class ConfigIdentifier { + final String subjectKey; + final String configKey; + + protected ConfigIdentifier(String subjectKey, String configKey) { + this.subjectKey = subjectKey; + this.configKey = configKey; + } + + @Override + public int hashCode() { + return Objects.hash(subjectKey, configKey); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ConfigIdentifier) { + final ConfigIdentifier other = (ConfigIdentifier) obj; + return Objects.equals(this.subjectKey, other.subjectKey) + && Objects.equals(this.configKey, other.configKey); + } + return false; + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/package-info.java new file mode 100644 index 00000000..38f76941 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/config/impl/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. + */ + +/** + * Implementation of the network configuration subsystem. + */ +package org.onosproject.net.config.impl; \ No newline at end of file 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 new file mode 100644 index 00000000..7900d185 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/BasicDeviceOperator.java @@ -0,0 +1,107 @@ +/* + * Copyright 2014-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.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.device.DefaultDeviceDescription; +import org.onosproject.net.device.DeviceDescription; +import org.slf4j.Logger; + +import java.util.Objects; + +/** + * Implementations of merge policies for various sources of device configuration + * information. This includes applications, provides, and network configurations. + */ +public final class BasicDeviceOperator implements ConfigOperator { + + protected static final double DEFAULT_COORD = -1.0; + private static final Logger log = getLogger(BasicDeviceOperator.class); + + private BasicDeviceOperator() { + } + + /** + * Generates a DeviceDescription containing fields from a DeviceDescription and + * a DeviceConfig. + * + * @param bdc the device config entity from network config + * @param descr a DeviceDescription + * @return DeviceDescription based on both sources + */ + public static DeviceDescription combine(BasicDeviceConfig bdc, DeviceDescription descr) { + if (bdc == null) { + return descr; + } + + Device.Type type = descr.type(); + if (bdc.type() != null && bdc.type() != type) { + type = bdc.type(); + } + + SparseAnnotations sa = combine(bdc, descr.annotations()); + return new DefaultDeviceDescription(descr.deviceURI(), type, descr.manufacturer(), + descr.hwVersion(), descr.swVersion(), + descr.serialNumber(), descr.chassisId(), sa); + } + + /** + * Generates an annotation from an existing annotation and DeviceConfig. + * + * @param bdc the device config entity from network config + * @param an the annotation + * @return annotation combining both sources + */ + public static SparseAnnotations combine(BasicDeviceConfig bdc, SparseAnnotations an) { + DefaultAnnotations.Builder newBuilder = DefaultAnnotations.builder(); + if (!Objects.equals(bdc.driver(), an.value(AnnotationKeys.DRIVER))) { + newBuilder.set(AnnotationKeys.DRIVER, bdc.driver()); + } + if (bdc.name() != null) { + newBuilder.set(AnnotationKeys.NAME, bdc.name()); + } + if (bdc.latitude() != DEFAULT_COORD) { + newBuilder.set(AnnotationKeys.LATITUDE, Double.toString(bdc.latitude())); + } + if (bdc.longitude() != DEFAULT_COORD) { + newBuilder.set(AnnotationKeys.LONGITUDE, Double.toString(bdc.longitude())); + } + if (bdc.rackAddress() != null) { + newBuilder.set(AnnotationKeys.RACK_ADDRESS, bdc.rackAddress()); + } + if (bdc.owner() != null) { + newBuilder.set(AnnotationKeys.OWNER, bdc.owner()); + } + DefaultAnnotations newAnnotations = newBuilder.build(); + return DefaultAnnotations.union(an, newAnnotations); + } + + public static DeviceDescription descriptionOf(Device device) { + checkNotNull(device, "Must supply non-null Device"); + return new DefaultDeviceDescription(device.id().uri(), device.type(), + device.manufacturer(), device.hwVersion(), + device.swVersion(), device.serialNumber(), + device.chassisId(), (SparseAnnotations) device.annotations()); + } +} 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 new file mode 100644 index 00000000..b0b3abe2 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/DeviceManager.java @@ -0,0 +1,765 @@ +/* + * Copyright 2014-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.device.impl; + +import com.google.common.collect.Lists; +import com.google.common.util.concurrent.Futures; + +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.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; +import org.onosproject.mastership.MastershipTerm; +import org.onosproject.mastership.MastershipTermService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Device; +import org.onosproject.net.Device.Type; +import org.onosproject.net.DeviceId; +import org.onosproject.net.MastershipRole; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.device.DefaultDeviceDescription; +import org.onosproject.net.device.DefaultPortDescription; +import org.onosproject.net.device.DeviceAdminService; +import org.onosproject.net.device.DeviceDescription; +import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceListener; +import org.onosproject.net.device.DeviceProvider; +import org.onosproject.net.device.DeviceProviderRegistry; +import org.onosproject.net.device.DeviceProviderService; +import org.onosproject.net.device.DeviceService; +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.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.*; + +/** + * Provides implementation of the device SB & NB APIs. + */ +@Component(immediate = true) +@Service +public class DeviceManager + extends AbstractListenerProviderRegistry + implements DeviceService, DeviceAdminService, DeviceProviderRegistry { + + private static final String DEVICE_ID_NULL = "Device ID cannot be null"; + private static final String PORT_NUMBER_NULL = "Port number cannot be null"; + private static final String DEVICE_DESCRIPTION_NULL = "Device description cannot be null"; + private static final String PORT_DESCRIPTION_NULL = "Port description cannot be null"; + private static final String PORT_DESC_LIST_NULL = "Port description list cannot be null"; + + private final Logger log = getLogger(getClass()); + + private final DeviceStoreDelegate delegate = new InternalStoreDelegate(); + + private final MastershipListener mastershipListener = new InternalMastershipListener(); + private NodeId localNodeId; + + private ScheduledExecutorService backgroundService; + + private final NetworkConfigListener networkConfigListener = new InternalNetworkConfigListener(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceStore store; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterService clusterService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected MastershipService mastershipService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected MastershipTermService termService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected NetworkConfigService networkConfigService; + + @Activate + public void activate() { + backgroundService = newSingleThreadScheduledExecutor(groupedThreads("onos/device", "manager-background")); + localNodeId = clusterService.getLocalNode().id(); + + store.setDelegate(delegate); + eventDispatcher.addSink(DeviceEvent.class, listenerRegistry); + mastershipService.addListener(mastershipListener); + networkConfigService.addListener(networkConfigListener); + + backgroundService.scheduleWithFixedDelay(() -> { + try { + mastershipCheck(); + } catch (Exception e) { + log.error("Exception thrown during integrity check", e); + } + }, 1, 1, TimeUnit.MINUTES); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + backgroundService.shutdown(); + networkConfigService.removeListener(networkConfigListener); + store.unsetDelegate(delegate); + mastershipService.removeListener(mastershipListener); + eventDispatcher.removeSink(DeviceEvent.class); + log.info("Stopped"); + } + + @Override + public int getDeviceCount() { + checkPermission(DEVICE_READ); + return store.getDeviceCount(); + } + + @Override + public Iterable getDevices() { + checkPermission(DEVICE_READ); + return store.getDevices(); + } + + @Override + public Iterable getAvailableDevices() { + checkPermission(DEVICE_READ); + return store.getAvailableDevices(); + } + + @Override + public Device getDevice(DeviceId deviceId) { + checkPermission(DEVICE_READ); + checkNotNull(deviceId, DEVICE_ID_NULL); + return store.getDevice(deviceId); + } + + @Override + public MastershipRole getRole(DeviceId deviceId) { + checkPermission(DEVICE_READ); + checkNotNull(deviceId, DEVICE_ID_NULL); + return mastershipService.getLocalRole(deviceId); + } + + @Override + public List getPorts(DeviceId deviceId) { + checkPermission(DEVICE_READ); + checkNotNull(deviceId, DEVICE_ID_NULL); + return store.getPorts(deviceId); + } + + @Override + public List getPortStatistics(DeviceId deviceId) { + checkPermission(DEVICE_READ); + checkNotNull(deviceId, DEVICE_ID_NULL); + return store.getPortStatistics(deviceId); + } + + @Override + public List getPortDeltaStatistics(DeviceId deviceId) { + checkPermission(DEVICE_READ); + checkNotNull(deviceId, DEVICE_ID_NULL); + return store.getPortDeltaStatistics(deviceId); + } + + @Override + public Port getPort(DeviceId deviceId, PortNumber portNumber) { + checkPermission(DEVICE_READ); + checkNotNull(deviceId, DEVICE_ID_NULL); + checkNotNull(portNumber, PORT_NUMBER_NULL); + return store.getPort(deviceId, portNumber); + } + + @Override + public boolean isAvailable(DeviceId deviceId) { + checkPermission(DEVICE_READ); + + checkNotNull(deviceId, DEVICE_ID_NULL); + return store.isAvailable(deviceId); + } + + // Check a device for control channel connectivity. + private boolean isReachable(DeviceId deviceId) { + if (deviceId == null) { + return false; + } + DeviceProvider provider = getProvider(deviceId); + if (provider != null) { + return provider.isReachable(deviceId); + } else { + log.debug("Provider not found for {}", deviceId); + return false; + } + } + + @Override + public void removeDevice(DeviceId deviceId) { + checkNotNull(deviceId, DEVICE_ID_NULL); + DeviceEvent event = store.removeDevice(deviceId); + if (event != null) { + log.info("Device {} administratively removed", deviceId); + post(event); + } + } + + @Override + protected DeviceProviderService createProviderService( + DeviceProvider provider) { + return new InternalDeviceProviderService(provider); + } + + /** + * Checks if all the reachable devices have a valid mastership role. + */ + private void mastershipCheck() { + log.debug("Checking mastership"); + for (Device device : getDevices()) { + final DeviceId deviceId = device.id(); + log.trace("Checking device {}", deviceId); + + if (!isReachable(deviceId)) { + continue; + } + + if (mastershipService.getLocalRole(deviceId) != NONE) { + continue; + } + + log.info("{} is reachable but did not have a valid role, reasserting", deviceId); + + // isReachable but was not MASTER or STANDBY, get a role and apply + // Note: NONE triggers request to MastershipService + reassertRole(deviceId, NONE); + } + } + + // Personalized device provider service issued to the supplied provider. + private class InternalDeviceProviderService + extends AbstractProviderService + implements DeviceProviderService { + + InternalDeviceProviderService(DeviceProvider provider) { + super(provider); + } + + /** + * Apply role in reaction to provider event. + * + * @param deviceId device identifier + * @param newRole new role to apply to the device + * @return true if the request was sent to provider + */ + private boolean applyRole(DeviceId deviceId, MastershipRole newRole) { + + if (newRole.equals(MastershipRole.NONE)) { + //no-op + return true; + } + + DeviceProvider provider = provider(); + if (provider == null) { + log.warn("Provider for {} was not found. Cannot apply role {}", + deviceId, newRole); + return false; + } + provider.roleChanged(deviceId, newRole); + // not triggering probe when triggered by provider service event + + return true; + } + + @Override + public void deviceConnected(DeviceId deviceId, + DeviceDescription deviceDescription) { + checkNotNull(deviceId, DEVICE_ID_NULL); + checkNotNull(deviceDescription, DEVICE_DESCRIPTION_NULL); + checkValidity(); + + BasicDeviceConfig cfg = networkConfigService.getConfig(deviceId, BasicDeviceConfig.class); + if (!isAllowed(cfg)) { + log.warn("Device {} is not allowed", deviceId); + return; + } + // Generate updated description and establish my Role + deviceDescription = BasicDeviceOperator.combine(cfg, deviceDescription); + Futures.getUnchecked(mastershipService.requestRoleFor(deviceId) + .thenAccept(role -> { + log.info("Local role is {} for {}", role, deviceId); + applyRole(deviceId, role); + })); + + DeviceEvent event = store.createOrUpdateDevice(provider().id(), deviceId, + deviceDescription); + log.info("Device {} connected", deviceId); + if (event != null) { + log.trace("event: {} {}", event.type(), event); + post(event); + } + } + + @Override + public void deviceDisconnected(DeviceId deviceId) { + checkNotNull(deviceId, DEVICE_ID_NULL); + checkValidity(); + + 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()))); + store.updatePorts(this.provider().id(), deviceId, descs); + try { + if (mastershipService.isLocalMaster(deviceId)) { + post(store.markOffline(deviceId)); + } + } catch (IllegalStateException e) { + log.warn("Failed to mark {} offline", deviceId); + // only the MASTER should be marking off-line in normal cases, + // but if I was the last STANDBY connection, etc. and no one else + // was there to mark the device offline, this instance may need to + // temporarily request for Master Role and mark offline. + + //there are times when this node will correctly have mastership, BUT + //that isn't reflected in the ClockManager before the device disconnects. + //we want to let go of the device anyways, so make sure this happens. + + // FIXME: Store semantics leaking out as IllegalStateException. + // Consider revising store API to handle this scenario. + CompletableFuture roleFuture = mastershipService.requestRoleFor(deviceId); + roleFuture.whenComplete((role, error) -> { + MastershipTerm term = termService.getMastershipTerm(deviceId); + // TODO: Move this type of check inside device clock manager, etc. + if (term != null && localNodeId.equals(term.master())) { + log.info("Retry marking {} offline", deviceId); + post(store.markOffline(deviceId)); + } else { + log.info("Failed again marking {} offline. {}", deviceId, role); + } + }); + } finally { + try { + //relinquish master role and ability to be backup. + mastershipService.relinquishMastership(deviceId).get(); + } catch (InterruptedException e) { + log.warn("Interrupted while reliquishing role for {}", deviceId); + Thread.currentThread().interrupt(); + } catch (ExecutionException e) { + log.error("Exception thrown while relinquishing role for {}", deviceId, e); + } + } + } + + @Override + public void updatePorts(DeviceId deviceId, + List portDescriptions) { + checkNotNull(deviceId, DEVICE_ID_NULL); + checkNotNull(portDescriptions, PORT_DESC_LIST_NULL); + checkValidity(); + if (!mastershipService.isLocalMaster(deviceId)) { + // Never been a master for this device + // any update will be ignored. + log.trace("Ignoring {} port updates on standby node. {}", deviceId, portDescriptions); + return; + } + portDescriptions = portDescriptions.stream() + .map(e -> consolidate(deviceId, e)) + .collect(Collectors.toList()); + List events = store.updatePorts(this.provider().id(), + deviceId, portDescriptions); + for (DeviceEvent event : events) { + post(event); + } + } + + @Override + public void portStatusChanged(DeviceId deviceId, + PortDescription portDescription) { + checkNotNull(deviceId, DEVICE_ID_NULL); + checkNotNull(portDescription, PORT_DESCRIPTION_NULL); + checkValidity(); + + if (!mastershipService.isLocalMaster(deviceId)) { + // Never been a master for this device + // any update will be ignored. + log.trace("Ignoring {} port update on standby node. {}", deviceId, + portDescription); + return; + } + portDescription = consolidate(deviceId, portDescription); + final DeviceEvent event = store.updatePortStatus(this.provider().id(), + deviceId, portDescription); + if (event != null) { + log.info("Device {} port {} status changed", deviceId, event.port().number()); + post(event); + } + } + + // merges the appropriate PortConfig with the description. + private PortDescription consolidate(DeviceId did, PortDescription desc) { + switch (desc.type()) { + case COPPER: + case VIRTUAL: + return desc; + default: + OpticalPortConfig opc = networkConfigService.getConfig( + new ConnectPoint(did, desc.portNumber()), OpticalPortConfig.class); + return OpticalPortOperator.combine(opc, desc); + } + } + + @Override + public void receivedRoleReply(DeviceId deviceId, MastershipRole requested, + MastershipRole response) { + // Several things can happen here: + // 1. request and response match + // 2. request and response don't match + // 3. MastershipRole and requested match (and 1 or 2 are true) + // 4. MastershipRole and requested don't match (and 1 or 2 are true) + // + // 2, 4, and 3 with case 2 are failure modes. + + // FIXME: implement response to this notification + + log.debug("got reply to a role request for {}: asked for {}, and got {}", + deviceId, requested, response); + + if (requested == null && response == null) { + // something was off with DeviceProvider, maybe check channel too? + log.warn("Failed to assert role [{}] onto Device {}", requested, deviceId); + mastershipService.relinquishMastership(deviceId); + return; + } + + if (Objects.equals(requested, response)) { + if (Objects.equals(requested, mastershipService.getLocalRole(deviceId))) { + return; + } else { + return; + // FIXME roleManager got the device to comply, but doesn't agree with + // the store; use the store's view, then try to reassert. + } + } else { + // we didn't get back what we asked for. Reelect someone else. + log.warn("Failed to assert role [{}] onto Device {}", response, deviceId); + if (response == MastershipRole.MASTER) { + mastershipService.relinquishMastership(deviceId); + // TODO: Shouldn't we be triggering event? + //final Device device = getDevice(deviceId); + //post(new DeviceEvent(DEVICE_MASTERSHIP_CHANGED, device)); + } + } + } + + @Override + public void updatePortStatistics(DeviceId deviceId, Collection portStatistics) { + checkNotNull(deviceId, DEVICE_ID_NULL); + checkNotNull(portStatistics, "Port statistics list cannot be null"); + checkValidity(); + + DeviceEvent event = store.updatePortStatistics(this.provider().id(), + deviceId, portStatistics); + post(event); + } + } + + // by default allowed, otherwise check flag + private boolean isAllowed(BasicDeviceConfig cfg) { + return (cfg == null || cfg.isAllowed()); + } + + // Applies the specified role to the device; ignores NONE + + /** + * Apply role to device and send probe if MASTER. + * + * @param deviceId device identifier + * @param newRole new role to apply to the device + * @return true if the request was sent to provider + */ + private boolean applyRoleAndProbe(DeviceId deviceId, MastershipRole newRole) { + if (newRole.equals(MastershipRole.NONE)) { + //no-op + return true; + } + + DeviceProvider provider = getProvider(deviceId); + if (provider == null) { + log.warn("Provider for {} was not found. Cannot apply role {}", deviceId, newRole); + return false; + } + provider.roleChanged(deviceId, newRole); + + if (newRole.equals(MastershipRole.MASTER)) { + // only trigger event when request was sent to provider + provider.triggerProbe(deviceId); + } + return true; + } + + /** + * Reaasert role for specified device connected to this node. + * + * @param did device identifier + * @param nextRole role to apply. If NONE is specified, + * it will ask mastership service for a role and apply it. + */ + private void reassertRole(final DeviceId did, + final MastershipRole nextRole) { + + MastershipRole myNextRole = nextRole; + if (myNextRole == NONE) { + mastershipService.requestRoleFor(did); + MastershipTerm term = termService.getMastershipTerm(did); + if (term != null && localNodeId.equals(term.master())) { + myNextRole = MASTER; + } else { + myNextRole = STANDBY; + } + } + + switch (myNextRole) { + case MASTER: + final Device device = getDevice(did); + if ((device != null) && !isAvailable(did)) { + //flag the device as online. Is there a better way to do this? + DefaultDeviceDescription deviceDescription + = new DefaultDeviceDescription(did.uri(), + device.type(), + device.manufacturer(), + device.hwVersion(), + device.swVersion(), + device.serialNumber(), + device.chassisId()); + DeviceEvent devEvent = + store.createOrUpdateDevice(device.providerId(), did, + deviceDescription); + post(devEvent); + } + // TODO: should apply role only if there is mismatch + log.debug("Applying role {} to {}", myNextRole, did); + if (!applyRoleAndProbe(did, MASTER)) { + log.warn("Unsuccessful applying role {} to {}", myNextRole, did); + // immediately failed to apply role + mastershipService.relinquishMastership(did); + // FIXME disconnect? + } + break; + case STANDBY: + log.debug("Applying role {} to {}", myNextRole, did); + if (!applyRoleAndProbe(did, STANDBY)) { + log.warn("Unsuccessful applying role {} to {}", myNextRole, did); + // immediately failed to apply role + mastershipService.relinquishMastership(did); + // FIXME disconnect? + } + break; + case NONE: + default: + // should never reach here + log.error("You didn't see anything. I did not exist."); + break; + } + } + + private void handleMastershipEvent(MastershipEvent event) { + if (event.type() != MastershipEvent.Type.MASTER_CHANGED) { + // Don't care if backup list changed. + return; + } + + final DeviceId did = event.subject(); + + // myRole suggested by MastershipService + MastershipRole myNextRole; + if (localNodeId.equals(event.roleInfo().master())) { + // confirm latest info + MastershipTerm term = termService.getMastershipTerm(did); + final boolean iHaveControl = term != null && localNodeId.equals(term.master()); + if (iHaveControl) { + myNextRole = MASTER; + } else { + myNextRole = STANDBY; + } + } else if (event.roleInfo().backups().contains(localNodeId)) { + myNextRole = STANDBY; + } else { + myNextRole = NONE; + } + + final boolean isReachable = isReachable(did); + if (!isReachable) { + // device is not connected to this node + if (myNextRole != NONE) { + log.warn("Node was instructed to be {} role for {}, " + + "but this node cannot reach the device. " + + "Relinquishing role. ", + myNextRole, did); + mastershipService.relinquishMastership(did); + } + return; + } + + // device is connected to this node: + if (store.getDevice(did) != null) { + reassertRole(did, myNextRole); + } else { + log.debug("Device is not yet/no longer in the store: {}", did); + } + } + + // Intercepts mastership events + private class InternalMastershipListener implements MastershipListener { + + @Override + public void event(MastershipEvent event) { + backgroundService.submit(() -> { + try { + handleMastershipEvent(event); + } catch (Exception e) { + log.warn("Failed to handle {}", event, e); + } + }); + } + } + + // Store delegate to re-post events emitted from the store. + private class InternalStoreDelegate implements DeviceStoreDelegate { + @Override + public void notify(DeviceEvent event) { + post(event); + } + } + + @Override + public Iterable getDevices(Type type) { + checkPermission(DEVICE_READ); + Set results = new HashSet<>(); + Iterable devices = store.getDevices(); + if (devices != null) { + devices.forEach(d -> { + if (type.equals(d.type())) { + results.add(d); + } + }); + } + return results; + } + + @Override + public Iterable getAvailableDevices(Type type) { + checkPermission(DEVICE_READ); + Set results = new HashSet<>(); + Iterable availableDevices = store.getAvailableDevices(); + if (availableDevices != null) { + availableDevices.forEach(d -> { + if (type.equals(d.type())) { + results.add(d); + } + }); + } + return results; + } + + private class InternalNetworkConfigListener implements NetworkConfigListener { + @Override + public boolean isRelevant(NetworkConfigEvent event) { + return (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED + || event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) + && (event.configClass().equals(BasicDeviceConfig.class) + || event.configClass().equals(OpticalPortConfig.class)); + } + + @Override + public void event(NetworkConfigEvent event) { + DeviceEvent de = null; + if (event.configClass().equals(BasicDeviceConfig.class)) { + log.info("Detected Device network config event {}", event.type()); + DeviceId did = (DeviceId) event.subject(); + BasicDeviceConfig cfg = networkConfigService.getConfig(did, BasicDeviceConfig.class); + + if (!isAllowed(cfg)) { + kickOutBadDevice(did); + } else { + Device dev = getDevice(did); + DeviceDescription desc = (dev == null) ? null : BasicDeviceOperator.descriptionOf(dev); + desc = BasicDeviceOperator.combine(cfg, desc); + if (getProvider(did) != null) { + de = store.createOrUpdateDevice(getProvider(did).id(), did, desc); + } + } + } + if (event.configClass().equals(OpticalPortConfig.class)) { + ConnectPoint cpt = (ConnectPoint) event.subject(); + DeviceId did = cpt.deviceId(); + Port dpt = getPort(did, cpt.port()); + + if (dpt != null) { + OpticalPortConfig opc = networkConfigService.getConfig(cpt, OpticalPortConfig.class); + PortDescription desc = OpticalPortOperator.descriptionOf(dpt); + desc = OpticalPortOperator.combine(opc, desc); + if (getProvider(did) != null) { + de = store.updatePortStatus(getProvider(did).id(), did, desc); + } + } + } + + if (de != null) { + post(de); + } + } + + // checks if the specified device is allowed by the BasicDeviceConfig + // and if not, removes it + private void kickOutBadDevice(DeviceId deviceId) { + Device badDevice = getDevice(deviceId); + if (badDevice != null) { + removeDevice(deviceId); + } + } + } +} 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 new file mode 100644 index 00000000..b2fd02c7 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/OpticalPortOperator.java @@ -0,0 +1,173 @@ +/* + * Copyright 2014-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.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.OpticalPortConfig; +import org.onosproject.net.AnnotationKeys; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.OchPort; +import org.onosproject.net.OduCltPort; +import org.onosproject.net.OmsPort; +import org.onosproject.net.Port; +import org.onosproject.net.PortNumber; +import org.onosproject.net.SparseAnnotations; +import org.onosproject.net.device.DefaultPortDescription; +import org.onosproject.net.device.OchPortDescription; +import org.onosproject.net.device.OduCltPortDescription; +import org.onosproject.net.device.OmsPortDescription; +import org.onosproject.net.device.PortDescription; +import org.slf4j.Logger; + +/** + * Implementations of merge policies for various sources of optical port + * configuration information. This includes applications, provides, and network + * configurations. + */ +public final class OpticalPortOperator implements ConfigOperator { + + private static final Logger log = getLogger(OpticalPortOperator.class); + + private OpticalPortOperator() { + } + + /** + * Generates a PortDescription containing fields from a PortDescription and + * an OpticalPortConfig. + * + * @param opc the port config entity from network config + * @param descr a PortDescription + * @return PortDescription based on both sources + */ + public static PortDescription combine(OpticalPortConfig opc, PortDescription descr) { + if (opc == null) { + return descr; + } + + PortNumber port = descr.portNumber(); + final String name = opc.name(); + final String numName = opc.numberName(); + // if the description is null, or the current description port name != config name, + // create a new PortNumber. + PortNumber newPort = null; + if (port == null) { + // try to get the portNumber from the numName. + if (!numName.isEmpty()) { + final long pn = Long.parseLong(numName); + newPort = (!name.isEmpty()) ? PortNumber.portNumber(pn, name) : PortNumber.portNumber(pn); + } else { + // we don't have defining info (a port number value) + throw new RuntimeException("Possible misconfig, bailing on handling for: \n\t" + descr); + } + } else if ((!name.isEmpty()) && !name.equals(port.name())) { + final long pn = (numName.isEmpty()) ? port.toLong() : Long.parseLong(numName); + newPort = PortNumber.portNumber(pn, name); + } + + // Port type won't change unless we're overwriting a port completely. + // Watch out for overwrites to avoid class cast craziness. + boolean noOwrite = opc.type() == descr.type(); + + SparseAnnotations sa = combine(opc, descr.annotations()); + if (noOwrite) { + return updateDescription((newPort == null) ? port : newPort, sa, descr); + } else { + // TODO: must reconstruct a different type of PortDescription. + log.info("Type rewrite from {} to {} required", descr.type(), opc.type()); + } + return descr; + } + + // updates a port description whose port type has not changed. + private static PortDescription updateDescription( + PortNumber port, SparseAnnotations sa, PortDescription descr) { + switch (descr.type()) { + case OMS: + OmsPortDescription oms = (OmsPortDescription) descr; + return new OmsPortDescription(port, oms.isEnabled(), oms.minFrequency(), + oms.maxFrequency(), oms.grid(), sa); + case OCH: + // We might need to update lambda below with STATIC_LAMBDA. + OchPortDescription och = (OchPortDescription) descr; + return new OchPortDescription(port, och.isEnabled(), och.signalType(), + och.isTunable(), och.lambda(), sa); + case ODUCLT: + OduCltPortDescription odu = (OduCltPortDescription) descr; + return new OduCltPortDescription(port, odu.isEnabled(), odu.signalType(), sa); + case PACKET: + case FIBER: + return new DefaultPortDescription(port, descr.isEnabled(), descr.type(), + descr.portSpeed(), sa); + default: + // this includes copper ports. + log.warn("Unsupported optical port type {} - can't update", descr.type()); + return descr; + } + } + + /** + * Generates an annotation from an existing annotation and OptcalPortConfig. + * + * @param opc the port config entity from network config + * @param an the annotation + * @return annotation combining both sources + */ + public static SparseAnnotations combine(OpticalPortConfig opc, SparseAnnotations an) { + DefaultAnnotations.Builder b = DefaultAnnotations.builder(); + if (!opc.staticPort().isEmpty()) { + b.set(AnnotationKeys.STATIC_PORT, opc.staticPort()); + } + if (opc.staticLambda().isPresent()) { + b.set(AnnotationKeys.STATIC_LAMBDA, String.valueOf(opc.staticLambda().get())); + } + // The following may not need to be carried. + if (!opc.name().isEmpty()) { + b.set(AnnotationKeys.PORT_NAME, opc.name()); + } + return DefaultAnnotations.union(an, b.build()); + } + + /** + * Returns a description built from an existing port. + * + * @param port the device port + * @return a PortDescription based on the port + */ + public static PortDescription descriptionOf(Port port) { + checkNotNull(port, "Must supply non-null Port"); + final PortNumber ptn = port.number(); + final boolean isup = port.isEnabled(); + final SparseAnnotations an = (SparseAnnotations) port.annotations(); + switch (port.type()) { + case OMS: + OmsPort oms = (OmsPort) port; + return new OmsPortDescription(ptn, isup, oms.minFrequency(), + oms.maxFrequency(), oms.grid(), an); + case OCH: + OchPort och = (OchPort) port; + return new OchPortDescription(ptn, isup, och.signalType(), + och.isTunable(), och.lambda(), an); + case ODUCLT: + OduCltPort odu = (OduCltPort) port; + return new OduCltPortDescription(ptn, isup, odu.signalType(), an); + default: + return new DefaultPortDescription(ptn, isup, port.type(), port.portSpeed(), an); + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/package-info.java new file mode 100644 index 00000000..23c21378 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/device/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Core subsystem for tracking global inventory of infrastructure devices. + */ +package org.onosproject.net.device.impl; diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/driver/impl/DriverManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/driver/impl/DriverManager.java new file mode 100644 index 00000000..53bf30a1 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/driver/impl/DriverManager.java @@ -0,0 +1,188 @@ +/* + * 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.driver.impl; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +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; +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; +import org.onosproject.net.DeviceId; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.driver.Behaviour; +import org.onosproject.net.driver.DefaultDriverData; +import org.onosproject.net.driver.DefaultDriverHandler; +import org.onosproject.net.driver.DefaultDriverProvider; +import org.onosproject.net.driver.Driver; +import org.onosproject.net.driver.DriverAdminService; +import org.onosproject.net.driver.DriverHandler; +import org.onosproject.net.driver.DriverProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.onlab.util.Tools.nullIsNotFound; +import static org.onosproject.net.AnnotationKeys.DRIVER; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.onosproject.security.AppPermission.Type.*; + + + +/** + * Manages inventory of device drivers. + */ +@Component(immediate = true) +@Service +public class DriverManager extends DefaultDriverProvider implements DriverAdminService { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private static final String NO_DRIVER = "Driver not found"; + private static final String NO_DEVICE = "Device not found"; + private static final String DEFAULT = "default"; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + private Set providers = Sets.newConcurrentHashSet(); + private Map driverByKey = Maps.newConcurrentMap(); + + @Activate + protected void activate() { + log.info("Started"); + } + + @Deactivate + protected void deactivate() { + log.info("Stopped"); + } + + + @Override + public Set getProviders() { + return ImmutableSet.copyOf(providers); + } + + @Override + public void registerProvider(DriverProvider provider) { + provider.getDrivers().forEach(driver -> { + addDrivers(provider.getDrivers()); + driverByKey.put(key(driver.manufacturer(), + driver.hwVersion(), + driver.swVersion()), driver); + }); + providers.add(provider); + } + + @Override + public void unregisterProvider(DriverProvider provider) { + provider.getDrivers().forEach(driver -> { + removeDrivers(provider.getDrivers()); + driverByKey.remove(key(driver.manufacturer(), + driver.hwVersion(), + driver.swVersion())); + }); + providers.remove(provider); + } + + @Override + public Set getDrivers() { + checkPermission(DRIVER_READ); + + ImmutableSet.Builder builder = ImmutableSet.builder(); + drivers.values().forEach(builder::add); + return builder.build(); + } + + @Override + public Set getDrivers(Class withBehaviour) { + checkPermission(DRIVER_READ); + + return drivers.values().stream() + .filter(d -> d.hasBehaviour(withBehaviour)) + .collect(Collectors.toSet()); + } + + @Override + public Driver getDriver(String driverName) { + checkPermission(DRIVER_READ); + + return nullIsNotFound(drivers.get(driverName), NO_DRIVER); + } + + @Override + public Driver getDriver(String mfr, String hw, String sw) { + checkPermission(DRIVER_READ); + + // First attempt a literal search. + Driver driver = driverByKey.get(key(mfr, hw, sw)); + if (driver != null) { + return driver; + } + + // Otherwise, sweep through the key space and attempt to match using + // regular expression matching. + Optional optional = driverByKey.values().stream() + .filter(d -> matches(d, mfr, hw, sw)).findFirst(); + + // If no matching driver is found, return default. + return optional.isPresent() ? optional.get() : drivers.get(DEFAULT); + } + + // Matches the given driver using ERE matching against the given criteria. + private boolean matches(Driver d, String mfr, String hw, String sw) { + // TODO: consider pre-compiling the expressions in the future + return mfr.matches(d.manufacturer()) && + hw.matches(d.hwVersion()) && + sw.matches(d.swVersion()); + } + + @Override + public Driver getDriver(DeviceId deviceId) { + checkPermission(DRIVER_READ); + + Device device = nullIsNotFound(deviceService.getDevice(deviceId), NO_DEVICE); + String driverName = device.annotations().value(DRIVER); + if (driverName != null) { + return getDriver(driverName); + } + return nullIsNotFound(getDriver(device.manufacturer(), + device.hwVersion(), device.swVersion()), + NO_DRIVER); + } + + @Override + public DriverHandler createHandler(DeviceId deviceId, String... credentials) { + checkPermission(DRIVER_WRITE); + + Driver driver = getDriver(deviceId); + return new DefaultDriverHandler(new DefaultDriverData(driver, deviceId)); + } + + // Produces a composite driver key using the specified components. + private String key(String mfr, String hw, String sw) { + return String.format("%s-%s-%s", mfr, hw, sw); + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/driver/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/driver/impl/package-info.java new file mode 100644 index 00000000..2006391a --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/driver/impl/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. + */ + +/** + * Implementation of the device driver management subsystem. + */ +package org.onosproject.net.driver.impl; \ No newline at end of file diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/edgeservice/impl/EdgeManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/edgeservice/impl/EdgeManager.java new file mode 100644 index 00000000..e992f7a4 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/edgeservice/impl/EdgeManager.java @@ -0,0 +1,241 @@ +/* + * Copyright 2014 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.edgeservice.impl; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +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; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; +import org.onosproject.event.AbstractListenerManager; +import org.onosproject.event.Event; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.edge.EdgePortEvent; +import org.onosproject.net.edge.EdgePortListener; +import org.onosproject.net.edge.EdgePortService; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.link.LinkEvent; +import org.onosproject.net.packet.DefaultOutboundPacket; +import org.onosproject.net.packet.OutboundPacket; +import org.onosproject.net.packet.PacketService; +import org.onosproject.net.topology.Topology; +import org.onosproject.net.topology.TopologyEvent; +import org.onosproject.net.topology.TopologyListener; +import org.onosproject.net.topology.TopologyService; +import org.slf4j.Logger; + +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import static org.onosproject.net.device.DeviceEvent.Type.*; +import static org.onosproject.net.edge.EdgePortEvent.Type.EDGE_PORT_ADDED; +import static org.onosproject.net.edge.EdgePortEvent.Type.EDGE_PORT_REMOVED; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * This is an implementation of the edge net service. + */ +@Component(immediate = true) +@Service +public class EdgeManager + extends AbstractListenerManager + implements EdgePortService { + + private final Logger log = getLogger(getClass()); + + private Topology topology; + + private final Map> connectionPoints = Maps.newConcurrentMap(); + + private final TopologyListener topologyListener = new InnerTopologyListener(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected PacketService packetService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected TopologyService topologyService; + + @Activate + public void activate() { + eventDispatcher.addSink(EdgePortEvent.class, listenerRegistry); + topologyService.addListener(topologyListener); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + eventDispatcher.removeSink(EdgePortEvent.class); + topologyService.removeListener(topologyListener); + log.info("Stopped"); + } + + @Override + public boolean isEdgePoint(ConnectPoint point) { + return !topologyService.isInfrastructure(topologyService.currentTopology(), point); + } + + @Override + public Iterable getEdgePoints() { + ImmutableSet.Builder builder = ImmutableSet.builder(); + connectionPoints.forEach((k, v) -> v.forEach(builder::add)); + return builder.build(); + } + + @Override + public Iterable getEdgePoints(DeviceId deviceId) { + ImmutableSet.Builder builder = ImmutableSet.builder(); + Set set = connectionPoints.get(deviceId); + if (set != null) { + set.forEach(builder::add); + } + return builder.build(); + } + + @Override + public void emitPacket(ByteBuffer data, Optional treatment) { + TrafficTreatment.Builder builder = treatment.isPresent() ? + DefaultTrafficTreatment.builder(treatment.get()) : + DefaultTrafficTreatment.builder(); + getEdgePoints().forEach(p -> packetService.emit(packet(builder, p, data))); + } + + @Override + public void emitPacket(DeviceId deviceId, ByteBuffer data, + Optional treatment) { + TrafficTreatment.Builder builder = treatment.isPresent() ? + DefaultTrafficTreatment.builder(treatment.get()) : + DefaultTrafficTreatment.builder(); + getEdgePoints(deviceId).forEach(p -> packetService.emit(packet(builder, p, data))); + } + + private OutboundPacket packet(TrafficTreatment.Builder builder, ConnectPoint point, ByteBuffer data) { + builder.setOutput(point.port()); + return new DefaultOutboundPacket(point.deviceId(), builder.build(), data); + } + + // Internal listener for topo events used to keep our edge-port cache + // up to date. + private class InnerTopologyListener implements TopologyListener { + @Override + public void event(TopologyEvent event) { + topology = event.subject(); + List triggers = event.reasons(); + if (triggers != null) { + triggers.forEach(reason -> { + if (reason instanceof DeviceEvent) { + processDeviceEvent((DeviceEvent) reason); + } else if (reason instanceof LinkEvent) { + processLinkEvent((LinkEvent) reason); + } + }); + } else { + //FIXME special case of preexisting edgeport & no triggerless events could cause this to never hit and + //never discover an edgeport that should have been discovered. + loadAllEdgePorts(); + } + } + } + + // Initial loading of the edge port cache. + private void loadAllEdgePorts() { + deviceService.getAvailableDevices().forEach(d -> deviceService.getPorts(d.id()) + .forEach(p -> addEdgePort(new ConnectPoint(d.id(), p.number())))); + } + + // Processes a link event by adding or removing its end-points in our cache. + private void processLinkEvent(LinkEvent event) { + if (event.type() == LinkEvent.Type.LINK_ADDED) { + removeEdgePort(event.subject().src()); + removeEdgePort(event.subject().dst()); + } else if (event.type() == LinkEvent.Type.LINK_REMOVED) { + addEdgePort(event.subject().src()); + addEdgePort(event.subject().dst()); + } + } + + // Processes a device event by adding or removing its end-points in our cache. + private void processDeviceEvent(DeviceEvent event) { + //FIXME handle the case where a device is suspended, this may or may not come up + DeviceEvent.Type type = event.type(); + DeviceId id = event.subject().id(); + + if (type == DEVICE_ADDED || + type == DEVICE_AVAILABILITY_CHANGED && deviceService.isAvailable(id)) { + // When device is added or becomes available, add all its ports + deviceService.getPorts(event.subject().id()) + .forEach(p -> addEdgePort(new ConnectPoint(id, p.number()))); + } else if (type == DEVICE_REMOVED || + type == DEVICE_AVAILABILITY_CHANGED && !deviceService.isAvailable(id)) { + // When device is removed or becomes unavailable, remove all its ports + deviceService.getPorts(event.subject().id()) + .forEach(p -> removeEdgePort(new ConnectPoint(id, p.number()))); + connectionPoints.remove(id); + + } else if (type == DeviceEvent.Type.PORT_ADDED || + type == PORT_UPDATED && event.port().isEnabled()) { + addEdgePort(new ConnectPoint(id, event.port().number())); + } else if (type == DeviceEvent.Type.PORT_REMOVED || + type == PORT_UPDATED && !event.port().isEnabled()) { + removeEdgePort(new ConnectPoint(id, event.port().number())); + } + } + + // Adds the specified connection point to the edge points if needed. + private void addEdgePort(ConnectPoint point) { + if (!topologyService.isInfrastructure(topology, point) && !point.port().isLogical()) { + Set set = connectionPoints.get(point.deviceId()); + if (set == null) { + set = Sets.newConcurrentHashSet(); + connectionPoints.put(point.deviceId(), set); + } + if (set.add(point)) { + post(new EdgePortEvent(EDGE_PORT_ADDED, point)); + } + } + } + + // Removes the specified connection point from the edge points. + private void removeEdgePort(ConnectPoint point) { + if (!point.port().isLogical()) { + Set set = connectionPoints.get(point.deviceId()); + if (set == null) { + return; + } + if (set.remove(point)) { + post(new EdgePortEvent(EDGE_PORT_REMOVED, point)); + } + if (set.isEmpty()) { + connectionPoints.remove(point.deviceId()); + } + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/edgeservice/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/edgeservice/impl/package-info.java new file mode 100644 index 00000000..fd867326 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/edgeservice/impl/package-info.java @@ -0,0 +1,4 @@ +/** + * Core subsystem for interacting with network edges. + */ +package org.onosproject.net.edgeservice.impl; \ No newline at end of file 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 new file mode 100644 index 00000000..a1d046c5 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/FlowRuleManager.java @@ -0,0 +1,593 @@ +/* + * Copyright 2014-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.impl; + +import com.google.common.base.Strings; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Iterables; +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; +import org.apache.felix.scr.annotations.Modified; +import org.apache.felix.scr.annotations.Property; +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.cfg.ComponentConfigService; +import org.onosproject.net.provider.AbstractListenerProviderRegistry; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.core.IdGenerator; +import org.onosproject.net.Device; +import org.onosproject.net.DeviceId; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.flow.CompletedBatchOperation; +import org.onosproject.net.flow.DefaultFlowEntry; +import org.onosproject.net.flow.FlowEntry; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.FlowRuleBatchEntry; +import org.onosproject.net.flow.FlowRuleBatchEvent; +import org.onosproject.net.flow.FlowRuleBatchOperation; +import org.onosproject.net.flow.FlowRuleBatchRequest; +import org.onosproject.net.flow.FlowRuleEvent; +import org.onosproject.net.flow.FlowRuleListener; +import org.onosproject.net.flow.FlowRuleOperation; +import org.onosproject.net.flow.FlowRuleOperations; +import org.onosproject.net.flow.FlowRuleOperationsContext; +import org.onosproject.net.flow.FlowRuleProvider; +import org.onosproject.net.flow.FlowRuleProviderRegistry; +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.provider.AbstractProviderService; +import org.osgi.service.component.ComponentContext; +import org.slf4j.Logger; + +import java.util.Collections; +import java.util.Dictionary; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.groupedThreads; +import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_ADD_REQUESTED; +import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVE_REQUESTED; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.slf4j.LoggerFactory.getLogger; +import static org.onosproject.security.AppPermission.Type.*; + + + +/** + * Provides implementation of the flow NB & SB APIs. + */ +@Component(immediate = true, enabled = true) +@Service +public class FlowRuleManager + extends AbstractListenerProviderRegistry + implements FlowRuleService, FlowRuleProviderRegistry { + + public static final String FLOW_RULE_NULL = "FlowRule cannot be null"; + private static final boolean ALLOW_EXTRANEOUS_RULES = false; + + @Property(name = "allowExtraneousRules", boolValue = ALLOW_EXTRANEOUS_RULES, + label = "Allow flow rules in switch not installed by ONOS") + private boolean allowExtraneousRules = ALLOW_EXTRANEOUS_RULES; + + private final Logger log = getLogger(getClass()); + + private final FlowRuleStoreDelegate delegate = new InternalStoreDelegate(); + + protected ExecutorService deviceInstallers = + Executors.newFixedThreadPool(32, groupedThreads("onos/flowservice", "device-installer-%d")); + + protected ExecutorService operationsService = + Executors.newFixedThreadPool(32, groupedThreads("onos/flowservice", "operations-%d")); + + private IdGenerator idGenerator; + + private Map pendingFlowOperations + = new ConcurrentHashMap<>(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected FlowRuleStore store; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ComponentConfigService cfgService; + + @Activate + public void activate(ComponentContext context) { + cfgService.registerProperties(getClass()); + idGenerator = coreService.getIdGenerator(FLOW_OP_TOPIC); + + modified(context); + + store.setDelegate(delegate); + eventDispatcher.addSink(FlowRuleEvent.class, listenerRegistry); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + cfgService.unregisterProperties(getClass(), false); + deviceInstallers.shutdownNow(); + operationsService.shutdownNow(); + store.unsetDelegate(delegate); + eventDispatcher.removeSink(FlowRuleEvent.class); + log.info("Stopped"); + } + + @Modified + public void modified(ComponentContext context) { + if (context == null) { + return; + } + + Dictionary properties = context.getProperties(); + + String s = Tools.get(properties, "allowExtraneousRules"); + allowExtraneousRules = Strings.isNullOrEmpty(s) ? ALLOW_EXTRANEOUS_RULES : Boolean.valueOf(s); + + if (allowExtraneousRules) { + log.info("Allowing flow rules not installed by ONOS"); + } + } + + @Override + public int getFlowRuleCount() { + checkPermission(FLOWRULE_READ); + return store.getFlowRuleCount(); + } + + @Override + public Iterable getFlowEntries(DeviceId deviceId) { + checkPermission(FLOWRULE_READ); + return store.getFlowEntries(deviceId); + } + + @Override + public void applyFlowRules(FlowRule... flowRules) { + checkPermission(FLOWRULE_WRITE); + + FlowRuleOperations.Builder builder = FlowRuleOperations.builder(); + for (int i = 0; i < flowRules.length; i++) { + builder.add(flowRules[i]); + } + apply(builder.build()); + } + + @Override + public void removeFlowRules(FlowRule... flowRules) { + checkPermission(FLOWRULE_WRITE); + + FlowRuleOperations.Builder builder = FlowRuleOperations.builder(); + for (int i = 0; i < flowRules.length; i++) { + builder.remove(flowRules[i]); + } + apply(builder.build()); + } + + @Override + public void removeFlowRulesById(ApplicationId id) { + checkPermission(FLOWRULE_WRITE); + removeFlowRules(Iterables.toArray(getFlowRulesById(id), FlowRule.class)); + } + + @Override + public Iterable getFlowRulesById(ApplicationId id) { + checkPermission(FLOWRULE_READ); + + Set flowEntries = Sets.newHashSet(); + for (Device d : deviceService.getDevices()) { + for (FlowEntry flowEntry : store.getFlowEntries(d.id())) { + if (flowEntry.appId() == id.id()) { + flowEntries.add(flowEntry); + } + } + } + return flowEntries; + } + + @Override + public Iterable getFlowRulesByGroupId(ApplicationId appId, short groupId) { + checkPermission(FLOWRULE_READ); + + Set matches = Sets.newHashSet(); + long toLookUp = ((long) appId.id() << 16) | groupId; + for (Device d : deviceService.getDevices()) { + for (FlowEntry flowEntry : store.getFlowEntries(d.id())) { + if ((flowEntry.id().value() >>> 32) == toLookUp) { + matches.add(flowEntry); + } + } + } + return matches; + } + + @Override + public void apply(FlowRuleOperations ops) { + checkPermission(FLOWRULE_WRITE); + operationsService.submit(new FlowOperationsProcessor(ops)); + } + + @Override + protected FlowRuleProviderService createProviderService( + FlowRuleProvider provider) { + return new InternalFlowRuleProviderService(provider); + } + + private class InternalFlowRuleProviderService + extends AbstractProviderService + implements FlowRuleProviderService { + + final Map lastSeen = Maps.newConcurrentMap(); + + protected InternalFlowRuleProviderService(FlowRuleProvider provider) { + super(provider); + } + + @Override + public void flowRemoved(FlowEntry flowEntry) { + checkNotNull(flowEntry, FLOW_RULE_NULL); + checkValidity(); + lastSeen.remove(flowEntry); + FlowEntry stored = store.getFlowEntry(flowEntry); + if (stored == null) { + log.debug("Rule already evicted from store: {}", flowEntry); + return; + } + Device device = deviceService.getDevice(flowEntry.deviceId()); + FlowRuleProvider frp = getProvider(device.providerId()); + FlowRuleEvent event = null; + switch (stored.state()) { + case ADDED: + case PENDING_ADD: + frp.applyFlowRule(stored); + break; + case PENDING_REMOVE: + case REMOVED: + event = store.removeFlowRule(stored); + break; + default: + break; + + } + if (event != null) { + log.debug("Flow {} removed", flowEntry); + post(event); + } + } + + + private void flowMissing(FlowEntry flowRule) { + checkNotNull(flowRule, FLOW_RULE_NULL); + checkValidity(); + Device device = deviceService.getDevice(flowRule.deviceId()); + FlowRuleProvider frp = getProvider(device.providerId()); + FlowRuleEvent event = null; + switch (flowRule.state()) { + case PENDING_REMOVE: + case REMOVED: + event = store.removeFlowRule(flowRule); + frp.removeFlowRule(flowRule); + break; + case ADDED: + case PENDING_ADD: + try { + frp.applyFlowRule(flowRule); + } catch (UnsupportedOperationException e) { + log.warn(e.getMessage()); + if (flowRule instanceof DefaultFlowEntry) { + ((DefaultFlowEntry) flowRule).setState(FlowEntry.FlowEntryState.FAILED); + } + } + break; + default: + log.debug("Flow {} has not been installed.", flowRule); + } + + if (event != null) { + log.debug("Flow {} removed", flowRule); + post(event); + } + + } + + + private void extraneousFlow(FlowRule flowRule) { + checkNotNull(flowRule, FLOW_RULE_NULL); + checkValidity(); + FlowRuleProvider frp = getProvider(flowRule.deviceId()); + frp.removeFlowRule(flowRule); + log.debug("Flow {} is on switch but not in store.", flowRule); + } + + + private void flowAdded(FlowEntry flowEntry) { + checkNotNull(flowEntry, FLOW_RULE_NULL); + checkValidity(); + + if (checkRuleLiveness(flowEntry, store.getFlowEntry(flowEntry))) { + + FlowRuleEvent event = store.addOrUpdateFlowRule(flowEntry); + if (event == null) { + log.debug("No flow store event generated."); + } else { + log.trace("Flow {} {}", flowEntry, event.type()); + post(event); + } + } else { + log.debug("Removing flow rules...."); + removeFlowRules(flowEntry); + } + + } + + private boolean checkRuleLiveness(FlowEntry swRule, FlowEntry storedRule) { + if (storedRule == null) { + return false; + } + if (storedRule.isPermanent()) { + return true; + } + + final long timeout = storedRule.timeout() * 1000; + final long currentTime = System.currentTimeMillis(); + if (storedRule.packets() != swRule.packets()) { + lastSeen.put(storedRule, currentTime); + return true; + } + if (!lastSeen.containsKey(storedRule)) { + // checking for the first time + lastSeen.put(storedRule, storedRule.lastSeen()); + // Use following if lastSeen attr. was removed. + //lastSeen.put(storedRule, currentTime); + } + Long last = lastSeen.get(storedRule); + if (last == null) { + // concurrently removed? let the liveness check fail + return false; + } + + if ((currentTime - last) <= timeout) { + return true; + } + return false; + } + + @Override + public void pushFlowMetrics(DeviceId deviceId, Iterable flowEntries) { + Map storedRules = Maps.newHashMap(); + store.getFlowEntries(deviceId).forEach(f -> storedRules.put(f, f)); + + for (FlowEntry rule : flowEntries) { + try { + FlowEntry storedRule = storedRules.remove(rule); + if (storedRule != null) { + if (storedRule.exactMatch(rule)) { + // we both have the rule, let's update some info then. + flowAdded(rule); + } else { + // the two rules are not an exact match - remove the + // switch's rule and install our rule + extraneousFlow(rule); + flowMissing(storedRule); + } + } else { + // the device has a rule the store does not have + if (!allowExtraneousRules) { + extraneousFlow(rule); + } + } + } catch (Exception e) { + log.debug("Can't process added or extra rule {}", e.getMessage()); + 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; + } + } + + } + + @Override + public void batchOperationCompleted(long batchId, CompletedBatchOperation operation) { + store.batchOperationComplete(FlowRuleBatchEvent.completed( + new FlowRuleBatchRequest(batchId, Collections.emptySet()), + operation + )); + } + } + + // Store delegate to re-post events emitted from the store. + private class InternalStoreDelegate implements FlowRuleStoreDelegate { + + + // TODO: Right now we only dispatch events at individual flowEntry level. + // It may be more efficient for also dispatch events as a batch. + @Override + public void notify(FlowRuleBatchEvent event) { + final FlowRuleBatchRequest request = event.subject(); + switch (event.type()) { + case BATCH_OPERATION_REQUESTED: + // Request has been forwarded to MASTER Node, and was + request.ops().stream().forEach( + op -> { + switch (op.operator()) { + + case ADD: + post(new FlowRuleEvent(RULE_ADD_REQUESTED, + op.target())); + break; + case REMOVE: + post(new FlowRuleEvent(RULE_REMOVE_REQUESTED, + op.target())); + break; + case MODIFY: + //TODO: do something here when the time comes. + break; + default: + log.warn("Unknown flow operation operator: {}", op.operator()); + } + } + ); + + DeviceId deviceId = event.deviceId(); + + FlowRuleBatchOperation batchOperation = + request.asBatchOperation(deviceId); + + FlowRuleProvider flowRuleProvider = getProvider(deviceId); + if (flowRuleProvider != null) { + flowRuleProvider.executeBatch(batchOperation); + } + + break; + + case BATCH_OPERATION_COMPLETED: + + FlowOperationsProcessor fops = pendingFlowOperations.remove( + event.subject().batchId()); + if (event.result().isSuccess()) { + if (fops != null) { + fops.satisfy(event.deviceId()); + } + } else { + fops.fail(event.deviceId(), event.result().failedItems()); + } + + break; + + default: + break; + } + } + } + + private class FlowOperationsProcessor implements Runnable { + + private final List> stages; + private final FlowRuleOperationsContext context; + private final FlowRuleOperations fops; + private final AtomicBoolean hasFailed = new AtomicBoolean(false); + + private Set pendingDevices; + + public FlowOperationsProcessor(FlowRuleOperations ops) { + this.stages = Lists.newArrayList(ops.stages()); + this.context = ops.callback(); + this.fops = ops; + pendingDevices = Sets.newConcurrentHashSet(); + } + + @Override + public void run() { + if (stages.size() > 0) { + process(stages.remove(0)); + } else if (!hasFailed.get() && context != null) { + context.onSuccess(fops); + } + } + + private void process(Set ops) { + Multimap perDeviceBatches = + ArrayListMultimap.create(); + + FlowRuleBatchEntry fbe; + for (FlowRuleOperation flowRuleOperation : ops) { + switch (flowRuleOperation.type()) { + // FIXME: Brian needs imagination when creating class names. + case ADD: + fbe = new FlowRuleBatchEntry( + FlowRuleBatchEntry.FlowRuleOperation.ADD, flowRuleOperation.rule()); + break; + case MODIFY: + fbe = new FlowRuleBatchEntry( + FlowRuleBatchEntry.FlowRuleOperation.MODIFY, flowRuleOperation.rule()); + break; + case REMOVE: + fbe = new FlowRuleBatchEntry( + FlowRuleBatchEntry.FlowRuleOperation.REMOVE, flowRuleOperation.rule()); + break; + default: + throw new UnsupportedOperationException("Unknown flow rule type " + flowRuleOperation.type()); + } + pendingDevices.add(flowRuleOperation.rule().deviceId()); + perDeviceBatches.put(flowRuleOperation.rule().deviceId(), fbe); + } + + + for (DeviceId deviceId : perDeviceBatches.keySet()) { + long id = idGenerator.getNewId(); + final FlowRuleBatchOperation b = new FlowRuleBatchOperation(perDeviceBatches.get(deviceId), + deviceId, id); + pendingFlowOperations.put(id, this); + deviceInstallers.submit(() -> store.storeBatch(b)); + } + } + + public void satisfy(DeviceId devId) { + pendingDevices.remove(devId); + if (pendingDevices.isEmpty()) { + operationsService.submit(this); + } + } + + + + public void fail(DeviceId devId, Set failures) { + hasFailed.set(true); + pendingDevices.remove(devId); + if (pendingDevices.isEmpty()) { + operationsService.submit(this); + } + + if (context != null) { + final FlowRuleOperations.Builder failedOpsBuilder = + FlowRuleOperations.builder(); + failures.stream().forEach(failedOpsBuilder::add); + + context.onError(failedOpsBuilder.build()); + } + } + + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/package-info.java new file mode 100644 index 00000000..69934b6f --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flow/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Core subsystem for tracking and manipulating global flow state. + */ +package org.onosproject.net.flow.impl; diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java new file mode 100644 index 00000000..a76a298f --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java @@ -0,0 +1,416 @@ +/* + * 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.flowobjective.impl; + +import com.google.common.collect.Maps; +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; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; +import org.onlab.osgi.DefaultServiceDirectory; +import org.onlab.osgi.ServiceDirectory; +import org.onlab.util.ItemNotFoundException; +import org.onosproject.cluster.ClusterService; +import org.onosproject.mastership.MastershipEvent; +import org.onosproject.mastership.MastershipListener; +import org.onosproject.mastership.MastershipService; +import org.onosproject.net.DeviceId; +import org.onosproject.net.behaviour.Pipeliner; +import org.onosproject.net.behaviour.PipelinerContext; +import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceListener; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.driver.DefaultDriverProviderService; +import org.onosproject.net.driver.DriverHandler; +import org.onosproject.net.driver.DriverService; +import org.onosproject.net.flow.FlowRuleService; +import org.onosproject.net.flowobjective.FilteringObjective; +import org.onosproject.net.flowobjective.FlowObjectiveService; +import org.onosproject.net.flowobjective.FlowObjectiveStore; +import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate; +import org.onosproject.net.flowobjective.ForwardingObjective; +import org.onosproject.net.flowobjective.NextObjective; +import org.onosproject.net.flowobjective.Objective; +import org.onosproject.net.flowobjective.ObjectiveError; +import org.onosproject.net.flowobjective.ObjectiveEvent; +import org.onosproject.net.group.GroupService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutorService; + +import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.concurrent.Executors.newFixedThreadPool; +import static org.onlab.util.Tools.groupedThreads; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.onosproject.security.AppPermission.Type.*; + + + +/** + * Provides implementation of the flow objective programming service. + */ +@Component(immediate = true) +@Service +public class FlowObjectiveManager implements FlowObjectiveService { + + public static final int INSTALL_RETRY_ATTEMPTS = 5; + public static final long INSTALL_RETRY_INTERVAL = 1000; // ms + + private final Logger log = LoggerFactory.getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DriverService driverService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected MastershipService mastershipService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterService clusterService; + + // Note: The following dependencies are added on behalf of the pipeline + // driver behaviours to assure these services are available for their + // initialization. + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected FlowRuleService flowRuleService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected GroupService groupService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected FlowObjectiveStore flowObjectiveStore; + + // Note: This must remain an optional dependency to allow re-install of default drivers. + // Note: For now disabled until we can move to OPTIONAL_UNARY dependency + // @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC) + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DefaultDriverProviderService defaultDriverService; + + private final FlowObjectiveStoreDelegate delegate = new InternalStoreDelegate(); + + private final Map driverHandlers = Maps.newConcurrentMap(); + private final Map pipeliners = Maps.newConcurrentMap(); + + private final PipelinerContext context = new InnerPipelineContext(); + private final MastershipListener mastershipListener = new InnerMastershipListener(); + private final DeviceListener deviceListener = new InnerDeviceListener(); + + protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory(); + + private Map> pendingForwards = Maps.newConcurrentMap(); + + private ExecutorService executorService; + + @Activate + protected void activate() { + executorService = newFixedThreadPool(4, groupedThreads("onos/objective-installer", "%d")); + flowObjectiveStore.setDelegate(delegate); + mastershipService.addListener(mastershipListener); + deviceService.addListener(deviceListener); + deviceService.getDevices().forEach(device -> setupPipelineHandler(device.id())); + log.info("Started"); + } + + @Deactivate + protected void deactivate() { + flowObjectiveStore.unsetDelegate(delegate); + mastershipService.removeListener(mastershipListener); + deviceService.removeListener(deviceListener); + executorService.shutdown(); + pipeliners.clear(); + driverHandlers.clear(); + log.info("Stopped"); + } + + /** + * Task that passes the flow objective down to the driver. The task will + * make a few attempts to find the appropriate driver, then eventually give + * up and report an error if no suitable driver could be found. + */ + private class ObjectiveInstaller implements Runnable { + private final DeviceId deviceId; + private final Objective objective; + + private final int numAttempts; + + public ObjectiveInstaller(DeviceId deviceId, Objective objective) { + this(deviceId, objective, 1); + } + + public ObjectiveInstaller(DeviceId deviceId, Objective objective, int attemps) { + this.deviceId = checkNotNull(deviceId); + this.objective = checkNotNull(objective); + this.numAttempts = checkNotNull(attemps); + } + + @Override + public void run() { + try { + Pipeliner pipeliner = getDevicePipeliner(deviceId); + + if (pipeliner != null) { + if (objective instanceof NextObjective) { + pipeliner.next((NextObjective) objective); + } else if (objective instanceof ForwardingObjective) { + pipeliner.forward((ForwardingObjective) objective); + } else { + pipeliner.filter((FilteringObjective) objective); + } + } else if (numAttempts < INSTALL_RETRY_ATTEMPTS) { + Thread.sleep(INSTALL_RETRY_INTERVAL); + executorService.submit(new ObjectiveInstaller(deviceId, objective, numAttempts + 1)); + } else { + // Otherwise we've tried a few times and failed, report an + // error back to the user. + objective.context().ifPresent( + c -> c.onError(objective, ObjectiveError.DEVICEMISSING)); + } + } catch (Exception e) { + log.warn("Exception while installing flow objective", e); + } + } + } + + @Override + public void filter(DeviceId deviceId, FilteringObjective filteringObjective) { + checkPermission(FLOWRULE_WRITE); + executorService.submit(new ObjectiveInstaller(deviceId, filteringObjective)); + } + + @Override + public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) { + checkPermission(FLOWRULE_WRITE); + if (queueObjective(deviceId, forwardingObjective)) { + return; + } + executorService.submit(new ObjectiveInstaller(deviceId, forwardingObjective)); + } + + @Override + public void next(DeviceId deviceId, NextObjective nextObjective) { + checkPermission(FLOWRULE_WRITE); + executorService.submit(new ObjectiveInstaller(deviceId, nextObjective)); + } + + @Override + public int allocateNextId() { + checkPermission(FLOWRULE_WRITE); + return flowObjectiveStore.allocateNextId(); + } + + @Override + public void initPolicy(String policy) {} + + private boolean queueObjective(DeviceId deviceId, ForwardingObjective fwd) { + if (fwd.nextId() != null && + flowObjectiveStore.getNextGroup(fwd.nextId()) == null) { + log.trace("Queuing forwarding objective for nextId {}", fwd.nextId()); + if (pendingForwards.putIfAbsent(fwd.nextId(), + Sets.newHashSet(new PendingNext(deviceId, fwd))) != null) { + Set pending = pendingForwards.get(fwd.nextId()); + pending.add(new PendingNext(deviceId, fwd)); + } + return true; + } + return false; + } + + // Retrieves the device pipeline behaviour from the cache. + private Pipeliner getDevicePipeliner(DeviceId deviceId) { + return pipeliners.get(deviceId); + } + + private void setupPipelineHandler(DeviceId deviceId) { + if (defaultDriverService == null) { + // We're not ready to go to work yet. + return; + } + + // Attempt to lookup the handler in the cache + DriverHandler handler = driverHandlers.get(deviceId); + cTime = now(); + + if (handler == null) { + try { + // Otherwise create it and if it has pipeline behaviour, cache it + handler = driverService.createHandler(deviceId); + dTime = now(); + if (!handler.driver().hasBehaviour(Pipeliner.class)) { + log.warn("Pipeline behaviour not supported for device {}", + deviceId); + return; + } + } catch (ItemNotFoundException e) { + log.warn("No applicable driver for device {}", deviceId); + return; + } + + driverHandlers.put(deviceId, handler); + eTime = now(); + } + + // Always (re)initialize the pipeline behaviour + log.info("Driver {} bound to device {} ... initializing driver", + handler.driver().name(), deviceId); + hTime = now(); + Pipeliner pipeliner = handler.behaviour(Pipeliner.class); + hbTime = now(); + pipeliner.init(deviceId, context); + pipeliners.putIfAbsent(deviceId, pipeliner); + } + + // Triggers driver setup when the local node becomes a device master. + private class InnerMastershipListener implements MastershipListener { + @Override + public void event(MastershipEvent event) { + switch (event.type()) { + case MASTER_CHANGED: + log.debug("mastership changed on device {}", event.subject()); + start = now(); + if (deviceService.isAvailable(event.subject())) { + setupPipelineHandler(event.subject()); + } + stopWatch(); + break; + case BACKUPS_CHANGED: + break; + default: + break; + } + } + } + + // Triggers driver setup when a device is (re)detected. + private class InnerDeviceListener implements DeviceListener { + @Override + public void event(DeviceEvent event) { + switch (event.type()) { + case DEVICE_ADDED: + case DEVICE_AVAILABILITY_CHANGED: + log.debug("Device either added or availability changed {}", + event.subject().id()); + start = now(); + if (deviceService.isAvailable(event.subject().id())) { + log.debug("Device is now available {}", event.subject().id()); + setupPipelineHandler(event.subject().id()); + } + stopWatch(); + break; + case DEVICE_UPDATED: + break; + case DEVICE_REMOVED: + break; + case DEVICE_SUSPENDED: + break; + case PORT_ADDED: + break; + case PORT_UPDATED: + break; + case PORT_REMOVED: + break; + default: + break; + } + } + } + + // Temporary mechanism to monitor pipeliner setup time-cost; there are + // intermittent time where this takes in excess of 2 seconds. Why? + private long start = 0, totals = 0, count = 0; + private long cTime, dTime, eTime, hTime, hbTime; + private static final long LIMIT = 500; + + private long now() { + return System.currentTimeMillis(); + } + + private void stopWatch() { + long duration = System.currentTimeMillis() - start; + totals += duration; + count += 1; + if (duration > LIMIT) { + log.info("Pipeline setup took {} ms; avg {} ms; cTime={}, dTime={}, eTime={}, hTime={}, hbTime={}", + duration, totals / count, diff(cTime), diff(dTime), diff(eTime), diff(hTime), diff(hbTime)); + } + } + + private long diff(long bTime) { + long diff = bTime - start; + return diff < 0 ? 0 : diff; + } + + // Processing context for initializing pipeline driver behaviours. + private class InnerPipelineContext implements PipelinerContext { + @Override + public ServiceDirectory directory() { + return serviceDirectory; + } + + @Override + public FlowObjectiveStore store() { + return flowObjectiveStore; + } + } + + private class InternalStoreDelegate implements FlowObjectiveStoreDelegate { + @Override + public void notify(ObjectiveEvent event) { + log.debug("Received notification of obj event {}", event); + Set pending = pendingForwards.remove(event.subject()); + + if (pending == null) { + log.debug("Nothing pending for this obj event"); + return; + } + + log.debug("Processing pending forwarding objectives {}", pending.size()); + + pending.forEach(p -> getDevicePipeliner(p.deviceId()) + .forward(p.forwardingObjective())); + + } + } + + /** + * Data class used to hold a pending forwarding objective that could not + * be processed because the associated next object was not present. + */ + private class PendingNext { + private final DeviceId deviceId; + private final ForwardingObjective fwd; + + public PendingNext(DeviceId deviceId, ForwardingObjective fwd) { + this.deviceId = deviceId; + this.fwd = fwd; + } + + public DeviceId deviceId() { + return deviceId; + } + + public ForwardingObjective forwardingObjective() { + return fwd; + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FilterTable.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FilterTable.java new file mode 100644 index 00000000..b46ce8b3 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FilterTable.java @@ -0,0 +1,61 @@ +/* + * 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.flowobjective.impl.composition; + +import org.onosproject.net.flowobjective.FilteringObjective; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Provides a table to store Fitler. + */ +public class FilterTable { + + protected Map filterMap; + + public FilterTable() { + this.filterMap = new HashMap<>(); + } + + public List updateFilter(FilteringObjective filteringObjective) { + List updates = new ArrayList<>(); + switch (filteringObjective.op()) { + case ADD: + this.filterMap.put(filteringObjective.id(), filteringObjective); + updates.add(filteringObjective); + break; + case REMOVE: + this.filterMap.remove(filteringObjective.id()); + updates.add(filteringObjective); + break; + default: + break; + } + return updates; + } + + public List updateFilter(List filteringObjectives) { + List updates = new ArrayList<>(); + for (FilteringObjective filteringObjective : filteringObjectives) { + updates.addAll(this.updateFilter(filteringObjective)); + } + return updates; + } + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionManager.java new file mode 100644 index 00000000..3ef98bd8 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionManager.java @@ -0,0 +1,439 @@ +/* + * 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.flowobjective.impl.composition; + +import com.google.common.collect.Maps; +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; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; +import org.onlab.osgi.DefaultServiceDirectory; +import org.onlab.osgi.ServiceDirectory; +import org.onlab.util.ItemNotFoundException; +import org.onosproject.cluster.ClusterService; +import org.onosproject.mastership.MastershipEvent; +import org.onosproject.mastership.MastershipListener; +import org.onosproject.mastership.MastershipService; +import org.onosproject.net.DeviceId; +import org.onosproject.net.behaviour.Pipeliner; +import org.onosproject.net.behaviour.PipelinerContext; +import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceListener; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.driver.DefaultDriverProviderService; +import org.onosproject.net.driver.DriverHandler; +import org.onosproject.net.driver.DriverService; +import org.onosproject.net.flow.FlowRuleService; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flowobjective.FilteringObjective; +import org.onosproject.net.flowobjective.FlowObjectiveService; +import org.onosproject.net.flowobjective.FlowObjectiveStore; +import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate; +import org.onosproject.net.flowobjective.ForwardingObjective; +import org.onosproject.net.flowobjective.NextObjective; +import org.onosproject.net.flowobjective.Objective; +import org.onosproject.net.flowobjective.ObjectiveError; +import org.onosproject.net.flowobjective.ObjectiveEvent; +import org.onosproject.net.group.GroupService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutorService; + +import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.concurrent.Executors.newFixedThreadPool; +import static org.onlab.util.Tools.groupedThreads; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.onosproject.security.AppPermission.Type.*; + + +/** + * Provides implementation of the flow objective programming service with composition feature. + * + * Note: This is an experimental, alternative implementation of the FlowObjectiveManager + * that supports composition. It can be enabled by setting the enable flag below to true, + * and you should also add "enabled = false" to the FlowObjectiveManager. + * + * The implementation relies a FlowObjectiveCompositionTree that is not yet distributed, + * so it will not have high availability and may break if device mastership changes. + * Therefore, it is safest to use this component in a single instance scenario. + * This comment will be removed when a distributed implementation is available. + */ +@Component(immediate = true, enabled = false) +@Service +public class FlowObjectiveCompositionManager implements FlowObjectiveService { + + public enum PolicyOperator { + Parallel, + Sequential, + Override, + Application + } + + public static final int INSTALL_RETRY_ATTEMPTS = 5; + public static final long INSTALL_RETRY_INTERVAL = 1000; // ms + + private final Logger log = LoggerFactory.getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DriverService driverService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected MastershipService mastershipService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ClusterService clusterService; + + // Note: The following dependencies are added on behalf of the pipeline + // driver behaviours to assure these services are available for their + // initialization. + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected FlowRuleService flowRuleService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected GroupService groupService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected FlowObjectiveStore flowObjectiveStore; + + // Note: This must remain an optional dependency to allow re-install of default drivers. + // Note: For now disabled until we can move to OPTIONAL_UNARY dependency + // @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY, policy = ReferencePolicy.DYNAMIC) + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DefaultDriverProviderService defaultDriverService; + + private final FlowObjectiveStoreDelegate delegate = new InternalStoreDelegate(); + + private final Map driverHandlers = Maps.newConcurrentMap(); + private final Map pipeliners = Maps.newConcurrentMap(); + + private final PipelinerContext context = new InnerPipelineContext(); + private final MastershipListener mastershipListener = new InnerMastershipListener(); + private final DeviceListener deviceListener = new InnerDeviceListener(); + + protected ServiceDirectory serviceDirectory = new DefaultServiceDirectory(); + + private Map> pendingForwards = Maps.newConcurrentMap(); + + private ExecutorService executorService; + + private String policy; + private Map deviceCompositionTreeMap; + + @Activate + protected void activate() { + executorService = newFixedThreadPool(4, groupedThreads("onos/objective-installer", "%d")); + flowObjectiveStore.setDelegate(delegate); + mastershipService.addListener(mastershipListener); + deviceService.addListener(deviceListener); + deviceService.getDevices().forEach(device -> setupPipelineHandler(device.id())); + deviceCompositionTreeMap = Maps.newConcurrentMap(); + log.info("Started"); + } + + @Deactivate + protected void deactivate() { + flowObjectiveStore.unsetDelegate(delegate); + mastershipService.removeListener(mastershipListener); + deviceService.removeListener(deviceListener); + executorService.shutdown(); + pipeliners.clear(); + driverHandlers.clear(); + deviceCompositionTreeMap.clear(); + log.info("Stopped"); + } + + /** + * Task that passes the flow objective down to the driver. The task will + * make a few attempts to find the appropriate driver, then eventually give + * up and report an error if no suitable driver could be found. + */ + private class ObjectiveInstaller implements Runnable { + private final DeviceId deviceId; + private final Objective objective; + + private final int numAttempts; + + public ObjectiveInstaller(DeviceId deviceId, Objective objective) { + this(deviceId, objective, 1); + } + + public ObjectiveInstaller(DeviceId deviceId, Objective objective, int attemps) { + this.deviceId = checkNotNull(deviceId); + this.objective = checkNotNull(objective); + this.numAttempts = checkNotNull(attemps); + } + + @Override + public void run() { + try { + Pipeliner pipeliner = getDevicePipeliner(deviceId); + + if (pipeliner != null) { + if (objective instanceof NextObjective) { + pipeliner.next((NextObjective) objective); + } else if (objective instanceof ForwardingObjective) { + pipeliner.forward((ForwardingObjective) objective); + } else { + pipeliner.filter((FilteringObjective) objective); + } + } else if (numAttempts < INSTALL_RETRY_ATTEMPTS) { + Thread.sleep(INSTALL_RETRY_INTERVAL); + executorService.submit(new ObjectiveInstaller(deviceId, objective, numAttempts + 1)); + } else { + // Otherwise we've tried a few times and failed, report an + // error back to the user. + objective.context().ifPresent( + c -> c.onError(objective, ObjectiveError.DEVICEMISSING)); + } + } catch (Exception e) { + log.warn("Exception while installing flow objective", e); + } + } + } + + @Override + public void filter(DeviceId deviceId, FilteringObjective filteringObjective) { + checkPermission(FLOWRULE_WRITE); + + List filteringObjectives + = this.deviceCompositionTreeMap.get(deviceId).updateFilter(filteringObjective); + for (FilteringObjective tmp : filteringObjectives) { + executorService.submit(new ObjectiveInstaller(deviceId, tmp)); + } + } + + @Override + public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) { + checkPermission(FLOWRULE_WRITE); + + if (queueObjective(deviceId, forwardingObjective)) { + return; + } + List forwardingObjectives + = this.deviceCompositionTreeMap.get(deviceId).updateForward(forwardingObjective); + for (ForwardingObjective tmp : forwardingObjectives) { + executorService.submit(new ObjectiveInstaller(deviceId, tmp)); + } + } + + @Override + public void next(DeviceId deviceId, NextObjective nextObjective) { + checkPermission(FLOWRULE_WRITE); + + List nextObjectives = this.deviceCompositionTreeMap.get(deviceId).updateNext(nextObjective); + for (NextObjective tmp : nextObjectives) { + executorService.submit(new ObjectiveInstaller(deviceId, tmp)); + } + } + + @Override + public int allocateNextId() { + checkPermission(FLOWRULE_WRITE); + + return flowObjectiveStore.allocateNextId(); + } + + private boolean queueObjective(DeviceId deviceId, ForwardingObjective fwd) { + if (fwd.nextId() != null && + flowObjectiveStore.getNextGroup(fwd.nextId()) == null) { + log.trace("Queuing forwarding objective for nextId {}", fwd.nextId()); + if (pendingForwards.putIfAbsent(fwd.nextId(), + Sets.newHashSet(new PendingNext(deviceId, fwd))) != null) { + Set pending = pendingForwards.get(fwd.nextId()); + pending.add(new PendingNext(deviceId, fwd)); + } + return true; + } + return false; + } + + @Override + public void initPolicy(String policy) { + this.policy = policy; + deviceService.getDevices().forEach(device -> + this.deviceCompositionTreeMap.put(device.id(), FlowObjectiveCompositionUtil.parsePolicyString(policy))); + log.info("Initialize policy {}", policy); + } + + // Retrieves the device pipeline behaviour from the cache. + private Pipeliner getDevicePipeliner(DeviceId deviceId) { + Pipeliner pipeliner = pipeliners.get(deviceId); + return pipeliner; + } + + private void setupPipelineHandler(DeviceId deviceId) { + if (defaultDriverService == null) { + // We're not ready to go to work yet. + return; + } + + // Attempt to lookup the handler in the cache + DriverHandler handler = driverHandlers.get(deviceId); + if (handler == null) { + try { + // Otherwise create it and if it has pipeline behaviour, cache it + handler = driverService.createHandler(deviceId); + if (!handler.driver().hasBehaviour(Pipeliner.class)) { + log.warn("Pipeline behaviour not supported for device {}", + deviceId); + return; + } + } catch (ItemNotFoundException e) { + log.warn("No applicable driver for device {}", deviceId); + return; + } + + driverHandlers.put(deviceId, handler); + } + + // Always (re)initialize the pipeline behaviour + log.info("Driver {} bound to device {} ... initializing driver", + handler.driver().name(), deviceId); + Pipeliner pipeliner = handler.behaviour(Pipeliner.class); + pipeliner.init(deviceId, context); + pipeliners.putIfAbsent(deviceId, pipeliner); + } + + // Triggers driver setup when the local node becomes a device master. + private class InnerMastershipListener implements MastershipListener { + @Override + public void event(MastershipEvent event) { + switch (event.type()) { + case MASTER_CHANGED: + log.debug("mastership changed on device {}", event.subject()); + if (deviceService.isAvailable(event.subject())) { + setupPipelineHandler(event.subject()); + } + break; + case BACKUPS_CHANGED: + break; + default: + break; + } + } + } + + // Triggers driver setup when a device is (re)detected. + private class InnerDeviceListener implements DeviceListener { + @Override + public void event(DeviceEvent event) { + switch (event.type()) { + case DEVICE_ADDED: + case DEVICE_AVAILABILITY_CHANGED: + log.debug("Device either added or availability changed {}", + event.subject().id()); + if (deviceService.isAvailable(event.subject().id())) { + log.debug("Device is now available {}", event.subject().id()); + setupPipelineHandler(event.subject().id()); + } + break; + case DEVICE_UPDATED: + break; + case DEVICE_REMOVED: + break; + case DEVICE_SUSPENDED: + break; + case PORT_ADDED: + break; + case PORT_UPDATED: + break; + case PORT_REMOVED: + break; + default: + break; + } + } + } + + // Processing context for initializing pipeline driver behaviours. + private class InnerPipelineContext implements PipelinerContext { + @Override + public ServiceDirectory directory() { + return serviceDirectory; + } + + @Override + public FlowObjectiveStore store() { + return flowObjectiveStore; + } + } + + private class InternalStoreDelegate implements FlowObjectiveStoreDelegate { + @Override + public void notify(ObjectiveEvent event) { + log.debug("Received notification of obj event {}", event); + Set pending = pendingForwards.remove(event.subject()); + + if (pending == null) { + log.debug("Nothing pending for this obj event"); + return; + } + + log.debug("Processing pending forwarding objectives {}", pending.size()); + + pending.forEach(p -> getDevicePipeliner(p.deviceId()) + .forward(p.forwardingObjective())); + + } + } + + /** + * Data class used to hold a pending forwarding objective that could not + * be processed because the associated next object was not present. + */ + private class PendingNext { + private final DeviceId deviceId; + private final ForwardingObjective fwd; + + public PendingNext(DeviceId deviceId, ForwardingObjective fwd) { + this.deviceId = deviceId; + this.fwd = fwd; + } + + public DeviceId deviceId() { + return deviceId; + } + + public ForwardingObjective forwardingObjective() { + return fwd; + } + } + + public static String forwardingObjectiveToString(ForwardingObjective forwardingObjective) { + String str = forwardingObjective.priority() + " "; + str += "selector( "; + for (Criterion criterion : forwardingObjective.selector().criteria()) { + str += criterion + " "; + } + str += ") treatment( "; + for (Instruction instruction : forwardingObjective.treatment().allInstructions()) { + str += instruction + " "; + } + str += ")"; + return str; + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionTree.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionTree.java new file mode 100644 index 00000000..152622b2 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionTree.java @@ -0,0 +1,271 @@ +/* + * 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.flowobjective.impl.composition; + +import org.onosproject.net.flowobjective.FilteringObjective; +import org.onosproject.net.flowobjective.ForwardingObjective; +import org.onosproject.net.flowobjective.NextObjective; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Provides a policy tree to store all flow tables for each device. + * + * Note: This class uses in-memory structures and is not yet distributed. + */ +public class FlowObjectiveCompositionTree { + + public FlowObjectiveCompositionManager.PolicyOperator operator; + public FlowObjectiveCompositionTree leftChild; + public FlowObjectiveCompositionTree rightChild; + public short applicationId; + protected FilterTable filterTable; + protected ForwardTable forwardTable; + protected NextTable nextTable; + + protected int priorityMultiplier; + protected int priorityAddend; + + public FlowObjectiveCompositionTree(short applicationId) { + this.operator = FlowObjectiveCompositionManager.PolicyOperator.Application; + this.leftChild = null; + this.rightChild = null; + this.applicationId = applicationId; + this.filterTable = new FilterTable(); + this.forwardTable = new ForwardTable(); + this.nextTable = new NextTable(); + this.priorityMultiplier = 10; + this.priorityAddend = 10; + } + + public FlowObjectiveCompositionTree(Character ch) { + switch (ch) { + case '+': + this.operator = FlowObjectiveCompositionManager.PolicyOperator.Parallel; + break; + case '>': + this.operator = FlowObjectiveCompositionManager.PolicyOperator.Sequential; + break; + case '/': + this.operator = FlowObjectiveCompositionManager.PolicyOperator.Override; + break; + default: + this.operator = FlowObjectiveCompositionManager.PolicyOperator.Application; + break; + } + this.leftChild = null; + this.rightChild = null; + this.applicationId = (short) -1; + this.filterTable = new FilterTable(); + this.forwardTable = new ForwardTable(); + this.nextTable = new NextTable(); + this.priorityMultiplier = 10; + this.priorityAddend = 10; + } + + protected List updateFilter(FilteringObjective filteringObjective) { + switch (this.operator) { + case Parallel: + return updateFilterParallel(filteringObjective); + case Sequential: + return updateFilterSequential(filteringObjective); + case Override: + return updateFilterOverride(filteringObjective); + case Application: + if (filteringObjective.appId().id() == this.applicationId) { + return this.filterTable.updateFilter(filteringObjective); + } else { + return new ArrayList<>(); + } + default: + return new ArrayList<>(); + } + } + + // Parallel composition: the filter set is the union of the children + protected List updateFilterParallel(FilteringObjective filteringObjective) { + List leftUpdates = this.leftChild.updateFilter(filteringObjective); + List rightUpdates = this.rightChild.updateFilter(filteringObjective); + + List updates = new ArrayList<>(); + updates.addAll(leftUpdates); + updates.addAll(rightUpdates); + + return this.filterTable.updateFilter(updates); + } + + // Sequential composition: the filter set is the filter set of the left child + protected List updateFilterSequential(FilteringObjective filteringObjective) { + List leftUpdates = this.leftChild.updateFilter(filteringObjective); + List rightUpdates = this.rightChild.updateFilter(filteringObjective); + return this.filterTable.updateFilter(leftUpdates); + } + + // Override composition: the filter set is the filter set of the left child + protected List updateFilterOverride(FilteringObjective filteringObjective) { + List leftUpdates = this.leftChild.updateFilter(filteringObjective); + List rightUpdates = this.rightChild.updateFilter(filteringObjective); + return this.filterTable.updateFilter(leftUpdates); + } + + public List updateForward(ForwardingObjective forwardingObjective) { + return this.updateForwardNode(forwardingObjective).toForwardingObjectiveList(); + } + + public ForwardUpdateTable updateForwardNode(ForwardingObjective forwardingObjective) { + switch (this.operator) { + case Parallel: + case Sequential: + case Override: + return updateForwardComposition(forwardingObjective); + case Application: + if (forwardingObjective.appId().id() == this.applicationId) { + return this.forwardTable.updateForward(forwardingObjective); + } else { + return (new ForwardUpdateTable()); + } + default: + return (new ForwardUpdateTable()); + } + } + + protected ForwardUpdateTable updateForwardComposition(ForwardingObjective forwardingObjective) { + ForwardUpdateTable leftUpdates = this.leftChild.updateForwardNode(forwardingObjective); + ForwardUpdateTable rightUpdates = this.rightChild.updateForwardNode(forwardingObjective); + + List addUpdates = new ArrayList<>(); + List removeUpdates = new ArrayList<>(); + // Handle ADD + if (this.operator == FlowObjectiveCompositionManager.PolicyOperator.Parallel + || this.operator == FlowObjectiveCompositionManager.PolicyOperator.Sequential) { + for (ForwardingObjective fo1 : leftUpdates.addObjectives) { + for (ForwardingObjective fo2 : this.rightChild.forwardTable.getForwardingObjectives()) { + ForwardingObjective composedFo = null; + if (this.operator == FlowObjectiveCompositionManager.PolicyOperator.Parallel) { + composedFo = FlowObjectiveCompositionUtil.composeParallel(fo1, fo2); + } else { + composedFo = FlowObjectiveCompositionUtil.composeSequential(fo1, fo2, this.priorityMultiplier); + } + if (composedFo != null) { + addUpdates.add(composedFo); + this.leftChild.forwardTable.addGeneratedParentForwardingObjective(fo1, composedFo); + this.rightChild.forwardTable.addGeneratedParentForwardingObjective(fo2, composedFo); + } + } + } + Collection leftTableWithoutAdd = FlowObjectiveCompositionUtil + .minusForwardingObjectives(this.leftChild.forwardTable.getForwardingObjectives(), + leftUpdates.addObjectives); + for (ForwardingObjective fo1 : leftTableWithoutAdd) { + for (ForwardingObjective fo2 : rightUpdates.addObjectives) { + ForwardingObjective composedFo = null; + if (this.operator == FlowObjectiveCompositionManager.PolicyOperator.Parallel) { + composedFo = FlowObjectiveCompositionUtil.composeParallel(fo1, fo2); + } else { + composedFo = FlowObjectiveCompositionUtil.composeSequential(fo1, fo2, this.priorityMultiplier); + } + if (composedFo != null) { + addUpdates.add(composedFo); + this.leftChild.forwardTable.addGeneratedParentForwardingObjective(fo1, composedFo); + this.rightChild.forwardTable.addGeneratedParentForwardingObjective(fo2, composedFo); + } + } + } + } else { + for (ForwardingObjective fo : leftUpdates.addObjectives) { + ForwardingObjective composedFo = FlowObjectiveCompositionUtil.composeOverride(fo, this.priorityAddend); + addUpdates.add(composedFo); + this.leftChild.forwardTable.addGeneratedParentForwardingObjective(fo, composedFo); + } + for (ForwardingObjective fo : rightUpdates.addObjectives) { + ForwardingObjective composedFo = FlowObjectiveCompositionUtil.composeOverride(fo, 0); + addUpdates.add(composedFo); + this.rightChild.forwardTable.addGeneratedParentForwardingObjective(fo, composedFo); + } + } + + // Handle REMOVE + for (ForwardingObjective fo : leftUpdates.removeObjectives) { + List fos = this.leftChild.forwardTable + .getGeneratedParentForwardingObjectiveForRemove(fo); + removeUpdates.addAll(fos); + } + this.leftChild.forwardTable.deleteGeneratedParentForwardingObjective(leftUpdates.removeObjectives); + for (ForwardingObjective fo : rightUpdates.removeObjectives) { + List fos = this.rightChild.forwardTable + .getGeneratedParentForwardingObjectiveForRemove(fo); + removeUpdates.addAll(fos); + } + this.rightChild.forwardTable.deleteGeneratedParentForwardingObjective(rightUpdates.removeObjectives); + + ForwardUpdateTable updates = new ForwardUpdateTable(); + updates.addUpdateTable(this.forwardTable.updateForward(addUpdates)); + updates.addUpdateTable(this.forwardTable.updateForward(removeUpdates)); + return updates; + } + + public List updateNext(NextObjective nextObjective) { + switch (this.operator) { + case Parallel: + case Sequential: + case Override: + return updateNextComposition(nextObjective); + case Application: + if (nextObjective.appId().id() == this.applicationId) { + return this.nextTable.updateNext(nextObjective); + } else { + return new ArrayList<>(); + } + default: + return new ArrayList<>(); + } + } + + // Next: the union of the children + protected List updateNextComposition(NextObjective nextObjective) { + List leftUpdates = this.leftChild.updateNext(nextObjective); + List rightUpdates = this.rightChild.updateNext(nextObjective); + + List updates = new ArrayList<>(); + updates.addAll(leftUpdates); + updates.addAll(rightUpdates); + + return this.nextTable.updateNext(updates); + } + + @Override + public String toString() { + String str = null; + switch (this.operator) { + case Parallel: + str = "(" + this.leftChild + "+" + this.rightChild + ")"; + break; + case Sequential: + str = "(" + this.leftChild + ">" + this.rightChild + ")"; + break; + case Override: + str = "(" + this.leftChild + "/" + this.rightChild + ")"; + break; + default: + str = " " + applicationId + " "; + break; + } + return str; + } + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java new file mode 100644 index 00000000..137aca1e --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionUtil.java @@ -0,0 +1,488 @@ +/* + * 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.flowobjective.impl.composition; + +import org.onlab.packet.IpPrefix; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.LambdaCriterion; +import org.onosproject.net.flow.criteria.OchSignalCriterion; +import org.onosproject.net.flow.criteria.EthCriterion; +import org.onosproject.net.flow.criteria.VlanIdCriterion; +import org.onosproject.net.flow.criteria.VlanPcpCriterion; +import org.onosproject.net.flow.criteria.MplsCriterion; +import org.onosproject.net.flow.criteria.IPCriterion; +import org.onosproject.net.flow.criteria.IPv6FlowLabelCriterion; +import org.onosproject.net.flow.criteria.Criteria; +import org.onosproject.net.flow.instructions.Instruction; +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.flowobjective.DefaultForwardingObjective; +import org.onosproject.net.flowobjective.ForwardingObjective; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; + +/** + * Provide util functions for FlowObjectiveComposition. + */ +public final class FlowObjectiveCompositionUtil { + + private FlowObjectiveCompositionUtil() {} + + // only work with VERSATILE + public static ForwardingObjective composeParallel(ForwardingObjective fo1, ForwardingObjective fo2) { + + TrafficSelector trafficSelector = intersectTrafficSelector(fo1.selector(), fo2.selector()); + if (trafficSelector == null) { + return null; + } + + TrafficTreatment trafficTreatment = unionTrafficTreatment(fo1.treatment(), fo2.treatment()); + + return DefaultForwardingObjective.builder() + .fromApp(fo1.appId()) + .makePermanent() + .withFlag(ForwardingObjective.Flag.VERSATILE) + .withPriority(fo1.priority() + fo2.priority()) + .withSelector(trafficSelector) + .withTreatment(trafficTreatment) + .add(); + } + + public static ForwardingObjective composeSequential(ForwardingObjective fo1, + ForwardingObjective fo2, + int priorityMultiplier) { + + TrafficSelector revertTrafficSelector = revertTreatmentSelector(fo1.treatment(), fo2.selector()); + if (revertTrafficSelector == null) { + return null; + } + + TrafficSelector trafficSelector = intersectTrafficSelector(fo1.selector(), revertTrafficSelector); + if (trafficSelector == null) { + return null; + } + + TrafficTreatment trafficTreatment = unionTrafficTreatment(fo1.treatment(), fo2.treatment()); + + return DefaultForwardingObjective.builder() + .fromApp(fo1.appId()) + .makePermanent() + .withFlag(ForwardingObjective.Flag.VERSATILE) + .withPriority(fo1.priority() * priorityMultiplier + fo2.priority()) + .withSelector(trafficSelector) + .withTreatment(trafficTreatment) + .add(); + } + + public static ForwardingObjective composeOverride(ForwardingObjective fo, int priorityAddend) { + return DefaultForwardingObjective.builder() + .fromApp(fo.appId()) + .makePermanent() + .withFlag(fo.flag()) + .withPriority(fo.priority() + priorityAddend) + .withSelector(fo.selector()) + .withTreatment(fo.treatment()) + .add(); + } + + public static TrafficSelector intersectTrafficSelector(TrafficSelector ts1, TrafficSelector ts2) { + + TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); + + Set ts1IntersectTs2 = getTypeSet(ts1); + ts1IntersectTs2.retainAll(getTypeSet(ts2)); + for (Criterion.Type type : ts1IntersectTs2) { + Criterion criterion = intersectCriterion(ts1.getCriterion(type), ts2.getCriterion(type)); + if (criterion == null) { + return null; + } else { + selectorBuilder.add(criterion); + } + } + + Set ts1MinusTs2 = getTypeSet(ts1); + ts1MinusTs2.removeAll(getTypeSet(ts2)); + for (Criterion.Type type : ts1MinusTs2) { + selectorBuilder.add(ts1.getCriterion(type)); + } + + Set ts2MinusTs1 = getTypeSet(ts2); + ts2MinusTs1.removeAll(getTypeSet(ts1)); + for (Criterion.Type type : ts2MinusTs1) { + selectorBuilder.add(ts2.getCriterion(type)); + } + + return selectorBuilder.build(); + } + + public static TrafficTreatment unionTrafficTreatment(TrafficTreatment tt1, TrafficTreatment tt2) { + + TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder(); + + for (Instruction instruction : tt1.allInstructions()) { + treatmentBuilder.add(instruction); + } + + for (Instruction instruction : tt2.allInstructions()) { + treatmentBuilder.add(instruction); + } + + return treatmentBuilder.build(); + } + + public static TrafficSelector revertTreatmentSelector(TrafficTreatment trafficTreatment, + TrafficSelector trafficSelector) { + + TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); + + Map criterionMap = new HashMap<>(); + for (Criterion criterion : trafficSelector.criteria()) { + criterionMap.put(criterion.type(), criterion); + } + + for (Instruction instruction : trafficTreatment.allInstructions()) { + switch (instruction.type()) { + case DROP: + return null; + case OUTPUT: + break; + case GROUP: + break; + case L0MODIFICATION: { + L0ModificationInstruction l0 = (L0ModificationInstruction) instruction; + switch (l0.subtype()) { + case LAMBDA: + if (criterionMap.containsKey(Criterion.Type.OCH_SIGID)) { + if (((LambdaCriterion) criterionMap.get((Criterion.Type.OCH_SIGID))).lambda() + == ((L0ModificationInstruction.ModLambdaInstruction) l0).lambda()) { + criterionMap.remove(Criterion.Type.OCH_SIGID); + } else { + return null; + } + } else { + break; + } + case OCH: + if (criterionMap.containsKey(Criterion.Type.OCH_SIGID)) { + if (((OchSignalCriterion) criterionMap.get((Criterion.Type.OCH_SIGID))).lambda() + .equals(((L0ModificationInstruction.ModOchSignalInstruction) l0).lambda())) { + criterionMap.remove(Criterion.Type.OCH_SIGID); + } else { + return null; + } + } else { + break; + } + default: + break; + } + break; + } + case L2MODIFICATION: { + L2ModificationInstruction l2 = (L2ModificationInstruction) instruction; + switch (l2.subtype()) { + case ETH_SRC: + if (criterionMap.containsKey(Criterion.Type.ETH_SRC)) { + if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_SRC))).mac() + .equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) { + criterionMap.remove(Criterion.Type.ETH_SRC); + } else { + return null; + } + } else { + break; + } + case ETH_DST: + if (criterionMap.containsKey(Criterion.Type.ETH_DST)) { + if (((EthCriterion) criterionMap.get((Criterion.Type.ETH_DST))).mac() + .equals(((L2ModificationInstruction.ModEtherInstruction) l2).mac())) { + criterionMap.remove(Criterion.Type.ETH_DST); + } else { + return null; + } + } else { + break; + } + case VLAN_ID: + if (criterionMap.containsKey(Criterion.Type.VLAN_VID)) { + if (((VlanIdCriterion) criterionMap.get((Criterion.Type.VLAN_VID))).vlanId() + .equals(((L2ModificationInstruction.ModVlanIdInstruction) l2).vlanId())) { + criterionMap.remove(Criterion.Type.VLAN_VID); + } else { + return null; + } + } else { + break; + } + case VLAN_PCP: + if (criterionMap.containsKey(Criterion.Type.VLAN_PCP)) { + if (((VlanPcpCriterion) criterionMap.get((Criterion.Type.VLAN_PCP))).priority() + == ((L2ModificationInstruction.ModVlanPcpInstruction) l2).vlanPcp()) { + criterionMap.remove(Criterion.Type.VLAN_PCP); + } else { + return null; + } + } else { + break; + } + case MPLS_LABEL: + if (criterionMap.containsKey(Criterion.Type.MPLS_LABEL)) { + if (((MplsCriterion) criterionMap.get((Criterion.Type.MPLS_LABEL))).label() + .equals(((L2ModificationInstruction.ModMplsLabelInstruction) l2).mplsLabel())) { + criterionMap.remove(Criterion.Type.ETH_DST); + } else { + return null; + } + } else { + break; + } + default: + break; + } + break; + } + case TABLE: + break; + case L3MODIFICATION: { + L3ModificationInstruction l3 = (L3ModificationInstruction) instruction; + switch (l3.subtype()) { + case IPV4_SRC: + if (criterionMap.containsKey(Criterion.Type.IPV4_SRC)) { + if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_SRC)).ip() + .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) { + criterionMap.remove(Criterion.Type.IPV4_SRC); + } else { + return null; + } + } else { + break; + } + case IPV4_DST: + if (criterionMap.containsKey(Criterion.Type.IPV4_DST)) { + if (((IPCriterion) criterionMap.get(Criterion.Type.IPV4_DST)).ip() + .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) { + criterionMap.remove(Criterion.Type.IPV4_DST); + } else { + return null; + } + } else { + break; + } + case IPV6_SRC: + if (criterionMap.containsKey(Criterion.Type.IPV6_SRC)) { + if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_SRC)).ip() + .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) { + criterionMap.remove(Criterion.Type.IPV6_SRC); + } else { + return null; + } + } else { + break; + } + case IPV6_DST: + if (criterionMap.containsKey(Criterion.Type.IPV6_DST)) { + if (((IPCriterion) criterionMap.get(Criterion.Type.IPV6_DST)).ip() + .contains(((L3ModificationInstruction.ModIPInstruction) l3).ip())) { + criterionMap.remove(Criterion.Type.IPV6_DST); + } else { + return null; + } + } else { + break; + } + case IPV6_FLABEL: + if (criterionMap.containsKey(Criterion.Type.IPV6_FLABEL)) { + if (((IPv6FlowLabelCriterion) criterionMap.get(Criterion.Type.IPV6_FLABEL)).flowLabel() + == (((L3ModificationInstruction.ModIPv6FlowLabelInstruction) l3).flowLabel())) { + criterionMap.remove(Criterion.Type.IPV4_SRC); + } else { + return null; + } + } else { + break; + } + default: + break; + } + break; + } + case METADATA: + break; + default: + break; + } + } + + for (Criterion criterion : criterionMap.values()) { + selectorBuilder.add(criterion); + } + + return selectorBuilder.build(); + } + + public static Set getTypeSet(TrafficSelector trafficSelector) { + Set typeSet = new HashSet<>(); + for (Criterion criterion : trafficSelector.criteria()) { + typeSet.add(criterion.type()); + } + return typeSet; + } + + public static Criterion intersectCriterion(Criterion c1, Criterion c2) { + switch (c1.type()) { + case IPV4_SRC: { + IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip()); + if (ipPrefix == null) { + return null; + } else { + return Criteria.matchIPSrc(ipPrefix); + } + } + case IPV4_DST: { + IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip()); + if (ipPrefix == null) { + return null; + } else { + return Criteria.matchIPDst(ipPrefix); + } + } + case IPV6_SRC: { + IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip()); + if (ipPrefix == null) { + return null; + } else { + return Criteria.matchIPv6Src(ipPrefix); + } + } + case IPV6_DST: { + IpPrefix ipPrefix = intersectIpPrefix(((IPCriterion) c1).ip(), ((IPCriterion) c2).ip()); + if (ipPrefix == null) { + return null; + } else { + return Criteria.matchIPv6Dst(ipPrefix); + } + } + default: + if (!c1.equals(c2)) { + return null; + } else { + return c1; + } + } + } + + public static IpPrefix intersectIpPrefix(IpPrefix ip1, IpPrefix ip2) { + if (ip1.contains(ip2)) { + return ip1; + } else if (ip2.contains(ip1)) { + return ip2; + } else { + return null; + } + } + + public static FlowObjectiveCompositionTree parsePolicyString(String policy) { + List postfix = transformToPostfixForm(policy); + return buildPolicyTree(postfix); + } + + private static List transformToPostfixForm(String policy) { + Stack stack = new Stack<>(); + List postfix = new ArrayList<>(); + + for (int i = 0; i < policy.length(); i++) { + Character ch = policy.charAt(i); + if (Character.isDigit(ch)) { + + int applicationId = ch - '0'; + while (i + 1 < policy.length() && Character.isDigit(policy.charAt(i + 1))) { + i++; + applicationId = applicationId * 10 + policy.charAt(i) - '0'; + } + + postfix.add(new FlowObjectiveCompositionTree((short) applicationId)); + } else if (ch == '(') { + stack.push(ch); + } else if (ch == ')') { + while (stack.peek() != '(') { + postfix.add(new FlowObjectiveCompositionTree(stack.pop())); + } + stack.pop(); + } else { + while (!stack.isEmpty() && compareOperatorPriority(stack.peek(), ch)) { + postfix.add(new FlowObjectiveCompositionTree(stack.pop())); + } + stack.push(ch); + } + } + while (!stack.isEmpty()) { + postfix.add(new FlowObjectiveCompositionTree(stack.pop())); + } + + return postfix; + } + + private static boolean compareOperatorPriority(char peek, char cur) { + if (peek == '/' && (cur == '+' || cur == '>' || cur == '/')) { + return true; + } else if (peek == '>' && (cur == '+' || cur == '>')) { + return true; + } else if (peek == '+' && cur == '+') { + return true; + } + return false; + } + + private static FlowObjectiveCompositionTree buildPolicyTree(List postfix) { + Stack stack = new Stack<>(); + for (FlowObjectiveCompositionTree node : postfix) { + if (node.operator == FlowObjectiveCompositionManager.PolicyOperator.Application) { + stack.push(node); + } else { + node.rightChild = stack.pop(); + node.leftChild = stack.pop(); + stack.push(node); + } + } + return stack.pop(); + } + + public static Collection minusForwardingObjectives(Collection fo1, + Collection fo2) { + Map map = new HashMap<>(); + for (ForwardingObjective fo : fo1) { + map.put(fo.id(), fo); + } + for (ForwardingObjective fo : fo2) { + map.remove(fo.id()); + } + return map.values(); + } + + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/ForwardTable.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/ForwardTable.java new file mode 100644 index 00000000..1384bbe2 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/ForwardTable.java @@ -0,0 +1,109 @@ +/* + * 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.flowobjective.impl.composition; + +import org.onosproject.net.flowobjective.DefaultForwardingObjective; +import org.onosproject.net.flowobjective.ForwardingObjective; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * Provides a table to store Forward. + */ +public class ForwardTable { + + protected Map forwardMap; + protected Map> generatedParentForwardingObjectiveMap; + + public ForwardTable() { + this.forwardMap = new HashMap<>(); + this.generatedParentForwardingObjectiveMap = new HashMap<>(); + } + + public ForwardUpdateTable updateForward(ForwardingObjective forwardingObjective) { + ForwardUpdateTable updates = new ForwardUpdateTable(); + switch (forwardingObjective.op()) { + case ADD: + this.forwardMap.put(forwardingObjectiveHash(forwardingObjective), forwardingObjective); + this.generatedParentForwardingObjectiveMap + .put(forwardingObjectiveHash(forwardingObjective), new ArrayList<>()); + updates.addObjectives.add(forwardingObjective); + break; + case REMOVE: + if (this.forwardMap.remove(forwardingObjectiveHash(forwardingObjective)) != null) { + updates.removeObjectives.add(forwardingObjective); + } + break; + default: + break; + } + return updates; + } + + public ForwardUpdateTable updateForward(List forwardingObjectives) { + ForwardUpdateTable updates = new ForwardUpdateTable(); + for (ForwardingObjective forwardingObjective : forwardingObjectives) { + updates.addUpdateTable(this.updateForward(forwardingObjective)); + } + return updates; + } + + public void addGeneratedParentForwardingObjective(ForwardingObjective child, ForwardingObjective parent) { + this.generatedParentForwardingObjectiveMap.get(forwardingObjectiveHash(child)).add(parent); + } + + public void deleteGeneratedParentForwardingObjective(List children) { + for (ForwardingObjective fo : children) { + this.generatedParentForwardingObjectiveMap.remove(forwardingObjectiveHash(fo)); + } + } + + private List getGeneratedParentForwardingObjective(ForwardingObjective child) { + return this.generatedParentForwardingObjectiveMap.get(forwardingObjectiveHash(child)); + } + + public List getGeneratedParentForwardingObjectiveForRemove(ForwardingObjective child) { + List fos = this.generatedParentForwardingObjectiveMap.get(forwardingObjectiveHash(child)); + List removeFos = new ArrayList<>(); + for (ForwardingObjective fo : fos) { + removeFos.add(DefaultForwardingObjective.builder() + .fromApp(fo.appId()) + .makePermanent() + .withFlag(fo.flag()) + .withPriority(fo.priority()) + .withSelector(fo.selector()) + .withTreatment(fo.treatment()) + .remove()); + } + return removeFos; + } + + public Collection getForwardingObjectives() { + return this.forwardMap.values(); + } + + public static int forwardingObjectiveHash(ForwardingObjective forwardingObjective) { + return Objects.hash(forwardingObjective.selector(), forwardingObjective.flag(), + forwardingObjective.permanent(), forwardingObjective.timeout(), + forwardingObjective.appId(), forwardingObjective.priority(), + forwardingObjective.nextId(), forwardingObjective.treatment()); + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/ForwardUpdateTable.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/ForwardUpdateTable.java new file mode 100644 index 00000000..9818cfd5 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/ForwardUpdateTable.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.net.flowobjective.impl.composition; + +import org.onosproject.net.flowobjective.ForwardingObjective; + +import java.util.ArrayList; +import java.util.List; + +/** + * Provides an update table for Forward. + */ +public class ForwardUpdateTable { + public List addObjectives; + public List removeObjectives; + + public ForwardUpdateTable() { + this.addObjectives = new ArrayList<>(); + this.removeObjectives = new ArrayList<>(); + } + + public void addUpdateTable(ForwardUpdateTable updateTable) { + this.addObjectives.addAll(updateTable.addObjectives); + this.removeObjectives.addAll(updateTable.removeObjectives); + } + + public List toForwardingObjectiveList() { + List forwardingObjectives = new ArrayList<>(); + forwardingObjectives.addAll(this.addObjectives); + forwardingObjectives.addAll(this.removeObjectives); + return forwardingObjectives; + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/NextTable.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/NextTable.java new file mode 100644 index 00000000..e2787edd --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/NextTable.java @@ -0,0 +1,61 @@ +/* + * 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.flowobjective.impl.composition; + +import org.onosproject.net.flowobjective.NextObjective; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Provides a table to store Next. + */ +public class NextTable { + + protected Map nextMap; + + public NextTable() { + this.nextMap = new HashMap<>(); + } + + public List updateNext(NextObjective nextObjective) { + List updates = new ArrayList<>(); + switch (nextObjective.op()) { + case ADD: + this.nextMap.put(nextObjective.id(), nextObjective); + updates.add(nextObjective); + break; + case REMOVE: + this.nextMap.remove(nextObjective.id()); + updates.add(nextObjective); + break; + default: + break; + } + return updates; + } + + public List updateNext(List nextObjectives) { + List updates = new ArrayList<>(); + for (NextObjective nextObjective : nextObjectives) { + updates.addAll(this.updateNext(nextObjective)); + } + return updates; + } + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/package-info.java new file mode 100644 index 00000000..da2a9850 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/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. + */ + +/** + * Prototype of a composition mechanism for flow objective composition. + */ +package org.onosproject.net.flowobjective.impl.composition; \ No newline at end of file diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/package-info.java new file mode 100644 index 00000000..c0779dc2 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/flowobjective/impl/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. + */ + +/** + * Implementations of the flow objective programming subsystem. + */ +package org.onosproject.net.flowobjective.impl; \ No newline at end of file diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java new file mode 100644 index 00000000..96e9b198 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/group/impl/GroupManager.java @@ -0,0 +1,318 @@ +/* + * 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.group.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.provider.AbstractListenerProviderRegistry; +import org.onosproject.core.ApplicationId; +import org.onosproject.net.DeviceId; +import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceListener; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.group.Group; +import org.onosproject.net.group.GroupBuckets; +import org.onosproject.net.group.GroupDescription; +import org.onosproject.net.group.GroupEvent; +import org.onosproject.net.group.GroupKey; +import org.onosproject.net.group.GroupListener; +import org.onosproject.net.group.GroupOperation; +import org.onosproject.net.group.GroupOperations; +import org.onosproject.net.group.GroupProvider; +import org.onosproject.net.group.GroupProviderRegistry; +import org.onosproject.net.group.GroupProviderService; +import org.onosproject.net.group.GroupService; +import org.onosproject.net.group.GroupStore; +import org.onosproject.net.group.GroupStore.UpdateType; +import org.onosproject.net.group.GroupStoreDelegate; +import org.onosproject.net.provider.AbstractProviderService; +import org.slf4j.Logger; + +import java.util.Collection; +import java.util.Collections; + +import static org.onosproject.security.AppGuard.checkPermission; +import static org.slf4j.LoggerFactory.getLogger; +import static org.onosproject.security.AppPermission.Type.*; + + + +/** + * Provides implementation of the group service APIs. + */ +@Component(immediate = true) +@Service +public class GroupManager + extends AbstractListenerProviderRegistry + implements GroupService, GroupProviderRegistry { + + private final Logger log = getLogger(getClass()); + + private final GroupStoreDelegate delegate = new InternalGroupStoreDelegate(); + private final DeviceListener deviceListener = new InternalDeviceListener(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected GroupStore store; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Activate + public void activate() { + store.setDelegate(delegate); + eventDispatcher.addSink(GroupEvent.class, listenerRegistry); + deviceService.addListener(deviceListener); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + store.unsetDelegate(delegate); + eventDispatcher.removeSink(GroupEvent.class); + log.info("Stopped"); + } + + /** + * Create a group in the specified device with the provided parameters. + * + * @param groupDesc group creation parameters + */ + @Override + public void addGroup(GroupDescription groupDesc) { + checkPermission(GROUP_WRITE); + store.storeGroupDescription(groupDesc); + } + + /** + * Return a group object associated to an application cookie. + *

+ * NOTE1: The presence of group object in the system does not + * guarantee that the "group" is actually created in device. + * GROUP_ADDED notification would confirm the creation of + * this group in data plane. + * + * @param deviceId device identifier + * @param appCookie application cookie to be used for lookup + * @return group associated with the application cookie or + * NULL if Group is not found for the provided cookie + */ + @Override + public Group getGroup(DeviceId deviceId, GroupKey appCookie) { + checkPermission(GROUP_READ); + return store.getGroup(deviceId, appCookie); + } + + /** + * Append buckets to existing group. The caller can optionally + * associate a new cookie during this updation. GROUP_UPDATED or + * GROUP_UPDATE_FAILED notifications would be provided along with + * cookie depending on the result of the operation on the device. + * + * @param deviceId device identifier + * @param oldCookie cookie to be used to retrieve the existing group + * @param buckets immutable list of group bucket to be added + * @param newCookie immutable cookie to be used post update operation + * @param appId Application Id + */ + @Override + public void addBucketsToGroup(DeviceId deviceId, + GroupKey oldCookie, + GroupBuckets buckets, + GroupKey newCookie, + ApplicationId appId) { + checkPermission(GROUP_WRITE); + store.updateGroupDescription(deviceId, + oldCookie, + UpdateType.ADD, + buckets, + newCookie); + } + + /** + * Remove buckets from existing group. The caller can optionally + * associate a new cookie during this updation. GROUP_UPDATED or + * GROUP_UPDATE_FAILED notifications would be provided along with + * cookie depending on the result of the operation on the device. + * + * @param deviceId device identifier + * @param oldCookie cookie to be used to retrieve the existing group + * @param buckets immutable list of group bucket to be removed + * @param newCookie immutable cookie to be used post update operation + * @param appId Application Id + */ + @Override + public void removeBucketsFromGroup(DeviceId deviceId, + GroupKey oldCookie, + GroupBuckets buckets, + GroupKey newCookie, + ApplicationId appId) { + checkPermission(GROUP_WRITE); + store.updateGroupDescription(deviceId, + oldCookie, + UpdateType.REMOVE, + buckets, + newCookie); + } + + /** + * Delete a group associated to an application cookie. + * GROUP_DELETED or GROUP_DELETE_FAILED notifications would be + * provided along with cookie depending on the result of the + * operation on the device. + * + * @param deviceId device identifier + * @param appCookie application cookie to be used for lookup + * @param appId Application Id + */ + @Override + public void removeGroup(DeviceId deviceId, + GroupKey appCookie, + ApplicationId appId) { + checkPermission(GROUP_WRITE); + store.deleteGroupDescription(deviceId, appCookie); + } + + /** + * Retrieve all groups created by an application in the specified device + * as seen by current controller instance. + * + * @param deviceId device identifier + * @param appId application id + * @return collection of immutable group objects created by the application + */ + @Override + public Iterable getGroups(DeviceId deviceId, + ApplicationId appId) { + checkPermission(GROUP_READ); + return store.getGroups(deviceId); + } + + @Override + public Iterable getGroups(DeviceId deviceId) { + checkPermission(GROUP_READ); + return store.getGroups(deviceId); + } + + @Override + protected GroupProviderService createProviderService(GroupProvider provider) { + return new InternalGroupProviderService(provider); + } + + private class InternalGroupStoreDelegate implements GroupStoreDelegate { + @Override + public void notify(GroupEvent event) { + final Group group = event.subject(); + GroupProvider groupProvider = + getProvider(group.deviceId()); + GroupOperations groupOps = null; + switch (event.type()) { + case GROUP_ADD_REQUESTED: + log.debug("GROUP_ADD_REQUESTED for Group {} on device {}", + group.id(), group.deviceId()); + GroupOperation groupAddOp = GroupOperation. + createAddGroupOperation(group.id(), + group.type(), + group.buckets()); + groupOps = new GroupOperations( + Collections.singletonList(groupAddOp)); + groupProvider.performGroupOperation(group.deviceId(), groupOps); + break; + + case GROUP_UPDATE_REQUESTED: + log.debug("GROUP_UPDATE_REQUESTED for Group {} on device {}", + group.id(), group.deviceId()); + GroupOperation groupModifyOp = GroupOperation. + createModifyGroupOperation(group.id(), + group.type(), + group.buckets()); + groupOps = new GroupOperations( + Collections.singletonList(groupModifyOp)); + groupProvider.performGroupOperation(group.deviceId(), groupOps); + break; + + case GROUP_REMOVE_REQUESTED: + log.debug("GROUP_REMOVE_REQUESTED for Group {} on device {}", + group.id(), group.deviceId()); + GroupOperation groupDeleteOp = GroupOperation. + createDeleteGroupOperation(group.id(), + group.type()); + groupOps = new GroupOperations( + Collections.singletonList(groupDeleteOp)); + groupProvider.performGroupOperation(group.deviceId(), groupOps); + break; + + case GROUP_ADDED: + case GROUP_UPDATED: + case GROUP_REMOVED: + case GROUP_ADD_FAILED: + case GROUP_UPDATE_FAILED: + case GROUP_REMOVE_FAILED: + post(event); + break; + + default: + break; + } + } + } + + private class InternalGroupProviderService + extends AbstractProviderService + implements GroupProviderService { + + protected InternalGroupProviderService(GroupProvider provider) { + super(provider); + } + + @Override + public void groupOperationFailed(DeviceId deviceId, GroupOperation operation) { + store.groupOperationFailed(deviceId, operation); + } + + @Override + public void pushGroupMetrics(DeviceId deviceId, + Collection groupEntries) { + log.trace("Received group metrics from device {}", deviceId); + checkValidity(); + store.pushGroupMetrics(deviceId, groupEntries); + } + } + + private class InternalDeviceListener implements DeviceListener { + + @Override + public void event(DeviceEvent event) { + switch (event.type()) { + case DEVICE_REMOVED: + case DEVICE_AVAILABILITY_CHANGED: + if (!deviceService.isAvailable(event.subject().id())) { + log.debug("Device {} became un available; clearing initial audit status", + event.type(), event.subject().id()); + store.deviceInitialAuditCompleted(event.subject().id(), false); + } + break; + + default: + break; + } + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/group/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/group/impl/package-info.java new file mode 100644 index 00000000..641ab441 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/group/impl/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. + */ + +/** + * Core subsystem for group state. + */ +package org.onosproject.net.group.impl; \ No newline at end of file diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/BasicHostOperator.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/BasicHostOperator.java new file mode 100644 index 00000000..68aa27f0 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/BasicHostOperator.java @@ -0,0 +1,84 @@ +/* + * Copyright 2014-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.host.impl; + +import static org.slf4j.LoggerFactory.getLogger; + +import org.slf4j.Logger; +import org.onosproject.net.config.ConfigOperator; +import org.onosproject.net.config.basics.BasicHostConfig; +import org.onosproject.net.AnnotationKeys; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.SparseAnnotations; +import org.onosproject.net.host.DefaultHostDescription; +import org.onosproject.net.host.HostDescription; + +/** + * Implementations of merge policies for various sources of host configuration + * information. This includes applications, provides, and network configurations. + */ +public final class BasicHostOperator implements ConfigOperator { + + protected static final double DEFAULT_COORD = -1.0; + private static final Logger log = getLogger(BasicHostOperator.class); + + private BasicHostOperator() { + } + + /** + * Generates a HostDescription containing fields from a HostDescription and + * a HostConfig. + * + * @param cfg the host config entity from network config + * @param descr a HostDescription + * @return HostDescription based on both sources + */ + public static HostDescription combine(BasicHostConfig cfg, HostDescription descr) { + if (cfg == null) { + return descr; + } + SparseAnnotations sa = combine(cfg, descr.annotations()); + return new DefaultHostDescription(descr.hwAddress(), descr.vlan(), descr.location(), + descr.ipAddress(), sa); + } + + /** + * Generates an annotation from an existing annotation and HostConfig. + * + * @param cfg the device config entity from network config + * @param an the annotation + * @return annotation combining both sources + */ + public static SparseAnnotations combine(BasicHostConfig cfg, SparseAnnotations an) { + DefaultAnnotations.Builder newBuilder = DefaultAnnotations.builder(); + if (cfg.name() != null) { + newBuilder.set(AnnotationKeys.NAME, cfg.name()); + } + if (cfg.latitude() != DEFAULT_COORD) { + newBuilder.set(AnnotationKeys.LATITUDE, Double.toString(cfg.latitude())); + } + if (cfg.longitude() != DEFAULT_COORD) { + newBuilder.set(AnnotationKeys.LONGITUDE, Double.toString(cfg.longitude())); + } + if (cfg.rackAddress() != null) { + newBuilder.set(AnnotationKeys.RACK_ADDRESS, cfg.rackAddress()); + } + if (cfg.owner() != null) { + newBuilder.set(AnnotationKeys.OWNER, cfg.owner()); + } + return DefaultAnnotations.union(an, newBuilder.build()); + } +} 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 new file mode 100644 index 00000000..99263381 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostManager.java @@ -0,0 +1,300 @@ +/* + * Copyright 2014 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.host.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.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; +import org.onosproject.incubator.net.intf.InterfaceService; +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.BasicHostConfig; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Host; +import org.onosproject.net.HostId; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.host.HostAdminService; +import org.onosproject.net.host.HostDescription; +import org.onosproject.net.host.HostEvent; +import org.onosproject.net.host.HostListener; +import org.onosproject.net.host.HostProvider; +import org.onosproject.net.host.HostProviderRegistry; +import org.onosproject.net.host.HostProviderService; +import org.onosproject.net.host.HostService; +import org.onosproject.net.host.HostStore; +import org.onosproject.net.host.HostStoreDelegate; +import org.onosproject.net.host.PortAddresses; +import org.onosproject.net.packet.PacketService; +import org.onosproject.net.provider.AbstractProviderService; +import org.slf4j.Logger; + +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.slf4j.LoggerFactory.getLogger; +import static org.onosproject.security.AppPermission.Type.*; + +/** + * Provides basic implementation of the host SB & NB APIs. + */ +@Component(immediate = true) +@Service +public class HostManager + extends AbstractListenerProviderRegistry + implements HostService, HostAdminService, HostProviderRegistry { + + private final Logger log = getLogger(getClass()); + + public static final String HOST_ID_NULL = "Host ID cannot be null"; + + private final NetworkConfigListener networkConfigListener = new InternalNetworkConfigListener(); + + private HostStoreDelegate delegate = new InternalStoreDelegate(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected HostStore store; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected PacketService packetService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected NetworkConfigService networkConfigService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected InterfaceService interfaceService; + + private HostMonitor monitor; + + @Activate + public void activate() { + store.setDelegate(delegate); + eventDispatcher.addSink(HostEvent.class, listenerRegistry); + networkConfigService.addListener(networkConfigListener); + monitor = new HostMonitor(packetService, this, interfaceService); + monitor.start(); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + store.unsetDelegate(delegate); + eventDispatcher.removeSink(HostEvent.class); + networkConfigService.removeListener(networkConfigListener); + log.info("Stopped"); + } + + @Override + protected HostProviderService createProviderService(HostProvider provider) { + monitor.registerHostProvider(provider); + return new InternalHostProviderService(provider); + } + + @Override + public int getHostCount() { + checkPermission(HOST_READ); + return store.getHostCount(); + } + + @Override + public Iterable getHosts() { + checkPermission(HOST_READ); + return store.getHosts(); + } + + @Override + public Host getHost(HostId hostId) { + checkPermission(HOST_READ); + checkNotNull(hostId, HOST_ID_NULL); + return store.getHost(hostId); + } + + @Override + public Set getHostsByVlan(VlanId vlanId) { + checkPermission(HOST_READ); + return store.getHosts(vlanId); + } + + @Override + public Set getHostsByMac(MacAddress mac) { + checkPermission(HOST_READ); + checkNotNull(mac, "MAC address cannot be null"); + return store.getHosts(mac); + } + + @Override + public Set getHostsByIp(IpAddress ip) { + checkPermission(HOST_READ); + checkNotNull(ip, "IP address cannot be null"); + return store.getHosts(ip); + } + + @Override + public Set getConnectedHosts(ConnectPoint connectPoint) { + checkPermission(HOST_READ); + checkNotNull(connectPoint, "Connection point cannot be null"); + return store.getConnectedHosts(connectPoint); + } + + @Override + public Set getConnectedHosts(DeviceId deviceId) { + checkPermission(HOST_READ); + checkNotNull(deviceId, "Device ID cannot be null"); + return store.getConnectedHosts(deviceId); + } + + @Override + public void startMonitoringIp(IpAddress ip) { + checkPermission(HOST_EVENT); + monitor.addMonitoringFor(ip); + } + + @Override + public void stopMonitoringIp(IpAddress ip) { + checkPermission(HOST_EVENT); + monitor.stopMonitoring(ip); + } + + @Override + public void requestMac(IpAddress ip) { + // FIXME!!!! Auto-generated method stub + } + + @Override + public void removeHost(HostId hostId) { + checkNotNull(hostId, HOST_ID_NULL); + HostEvent event = store.removeHost(hostId); + if (event != null) { + post(event); + } + } + + @Override + public void bindAddressesToPort(PortAddresses addresses) { + store.updateAddressBindings(addresses); + } + + @Override + public void unbindAddressesFromPort(PortAddresses portAddresses) { + store.removeAddressBindings(portAddresses); + } + + @Override + public void clearAddresses(ConnectPoint connectPoint) { + store.clearAddressBindings(connectPoint); + } + + @Override + public Set getAddressBindings() { + checkPermission(HOST_READ); + return store.getAddressBindings(); + } + + @Override + public Set getAddressBindingsForPort(ConnectPoint connectPoint) { + checkPermission(HOST_READ); + return store.getAddressBindingsForPort(connectPoint); + } + + // Personalized host provider service issued to the supplied provider. + private class InternalHostProviderService + extends AbstractProviderService + implements HostProviderService { + InternalHostProviderService(HostProvider provider) { + super(provider); + } + + @Override + public void hostDetected(HostId hostId, HostDescription hostDescription) { + checkNotNull(hostId, HOST_ID_NULL); + checkValidity(); + hostDescription = validateHost(hostDescription, hostId); + HostEvent event = store.createOrUpdateHost(provider().id(), hostId, + hostDescription); + if (event != null) { + post(event); + } + } + + // returns a HostDescription made from the union of the BasicHostConfig + // annotations if it exists + private HostDescription validateHost(HostDescription hostDescription, HostId hostId) { + BasicHostConfig cfg = networkConfigService.getConfig(hostId, BasicHostConfig.class); + checkState(cfg == null || cfg.isAllowed(), "Host {} is not allowed", hostId); + + return BasicHostOperator.combine(cfg, hostDescription); + } + + @Override + public void hostVanished(HostId hostId) { + checkNotNull(hostId, HOST_ID_NULL); + checkValidity(); + HostEvent event = store.removeHost(hostId); + if (event != null) { + post(event); + } + } + } + + // Store delegate to re-post events emitted from the store. + private class InternalStoreDelegate implements HostStoreDelegate { + @Override + public void notify(HostEvent event) { + post(event); + } + } + + // listens for NetworkConfigEvents of type BasicHostConfig and removes + // links that the config does not allow + private class InternalNetworkConfigListener implements NetworkConfigListener { + @Override + public void event(NetworkConfigEvent event) { + if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED || + event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) && + event.configClass().equals(BasicHostConfig.class)) { + log.info("Detected Host network config event {}", event.type()); + kickOutBadHost(((HostId) event.subject())); + } + } + } + + // checks if the specified host is allowed by the BasicHostConfig + // and if not, removes it + private void kickOutBadHost(HostId hostId) { + BasicHostConfig cfg = networkConfigService.getConfig(hostId, BasicHostConfig.class); + if (cfg != null && !cfg.isAllowed()) { + Host badHost = getHost(hostId); + if (badHost != null) { + removeHost(hostId); + } else { + log.info("Failed removal: Host {} does not exist", hostId); + } + } + } +} diff --git a/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 new file mode 100644 index 00000000..fe252368 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/HostMonitor.java @@ -0,0 +1,288 @@ +/* + * Copyright 2014-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.host.impl; + +import org.jboss.netty.util.Timeout; +import org.jboss.netty.util.TimerTask; +import org.onlab.packet.ARP; +import org.onlab.packet.Ethernet; +import org.onlab.packet.ICMP6; +import org.onlab.packet.IPv6; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; +import org.onlab.packet.ndp.NeighborDiscoveryOptions; +import org.onlab.packet.ndp.NeighborSolicitation; +import org.onlab.util.Timer; +import org.onosproject.incubator.net.intf.Interface; +import org.onosproject.incubator.net.intf.InterfaceService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Host; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.Instructions; +import org.onosproject.net.host.HostProvider; +import org.onosproject.net.host.InterfaceIpAddress; +import org.onosproject.net.packet.DefaultOutboundPacket; +import org.onosproject.net.packet.OutboundPacket; +import org.onosproject.net.packet.PacketService; +import org.onosproject.net.provider.ProviderId; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; + +/** + * Monitors hosts on the dataplane to detect changes in host data. + *

+ * The HostMonitor can monitor hosts that have already been detected for + * changes. At an application's request, it can also monitor and actively + * probe for hosts that have not yet been detected (specified by IP address). + *

+ */ +public class HostMonitor implements TimerTask { + private PacketService packetService; + private HostManager hostManager; + private InterfaceService interfaceService; + + private final Set monitoredAddresses; + + private final ConcurrentMap hostProviders; + + private static final long DEFAULT_PROBE_RATE = 30000; // milliseconds + private static final byte[] ZERO_MAC_ADDRESS = MacAddress.ZERO.toBytes(); + private long probeRate = DEFAULT_PROBE_RATE; + + private Timeout timeout; + + /** + * Creates a new host monitor. + * + * @param packetService packet service used to send packets on the data plane + * @param hostManager host manager used to look up host information and + * probe existing hosts + * @param interfaceService interface service for interface information + */ + public HostMonitor(PacketService packetService, HostManager hostManager, + InterfaceService interfaceService) { + + this.packetService = packetService; + this.hostManager = hostManager; + this.interfaceService = interfaceService; + + monitoredAddresses = Collections.newSetFromMap(new ConcurrentHashMap<>()); + hostProviders = new ConcurrentHashMap<>(); + } + + /** + * Adds an IP address to be monitored by the host monitor. The monitor will + * periodically probe the host to detect changes. + * + * @param ip IP address of the host to monitor + */ + void addMonitoringFor(IpAddress ip) { + monitoredAddresses.add(ip); + } + + /** + * Stops monitoring the given IP address. + * + * @param ip IP address to stop monitoring on + */ + void stopMonitoring(IpAddress ip) { + monitoredAddresses.remove(ip); + } + + /** + * Starts the host monitor. Does nothing if the monitor is already running. + */ + void start() { + synchronized (this) { + if (timeout == null) { + timeout = Timer.getTimer().newTimeout(this, 0, TimeUnit.MILLISECONDS); + } + } + } + + /** + * Stops the host monitor. + */ + void shutdown() { + synchronized (this) { + timeout.cancel(); + timeout = null; + } + } + + /** + * Registers a host provider with the host monitor. The monitor can use the + * provider to probe hosts. + * + * @param provider the host provider to register + */ + void registerHostProvider(HostProvider provider) { + hostProviders.put(provider.id(), provider); + } + + @Override + public void run(Timeout timeout) throws Exception { + for (IpAddress ip : monitoredAddresses) { + Set hosts = hostManager.getHostsByIp(ip); + + if (hosts.isEmpty()) { + sendArpNdpRequest(ip); + } else { + for (Host host : hosts) { + HostProvider provider = hostProviders.get(host.providerId()); + if (provider == null) { + hostProviders.remove(host.providerId(), null); + } else { + provider.triggerProbe(host); + } + } + } + } + + this.timeout = Timer.getTimer().newTimeout(this, probeRate, TimeUnit.MILLISECONDS); + } + + /** + * Sends an ARP or Neighbor Discovery Protocol request for the given IP + * address. + * + * @param targetIp IP address to send the request for + */ + private void sendArpNdpRequest(IpAddress targetIp) { + Interface intf = interfaceService.getMatchingInterface(targetIp); + + if (intf == null) { + return; + } + + for (InterfaceIpAddress ia : intf.ipAddresses()) { + if (ia.subnetAddress().contains(targetIp)) { + sendArpNdpProbe(intf.connectPoint(), targetIp, ia.ipAddress(), + intf.mac(), intf.vlan()); + } + } + } + + private void sendArpNdpProbe(ConnectPoint connectPoint, + IpAddress targetIp, + IpAddress sourceIp, MacAddress sourceMac, + VlanId vlan) { + Ethernet probePacket = null; + + if (targetIp.isIp4()) { + // IPv4: Use ARP + probePacket = buildArpRequest(targetIp, sourceIp, sourceMac, + vlan); + } else { + // IPv6: Use Neighbor Discovery + probePacket = buildNdpRequest(targetIp, sourceIp, sourceMac, + vlan); + } + + List instructions = new ArrayList<>(); + instructions.add(Instructions.createOutput(connectPoint.port())); + + TrafficTreatment treatment = DefaultTrafficTreatment.builder() + .setOutput(connectPoint.port()) + .build(); + + OutboundPacket outboundPacket = + new DefaultOutboundPacket(connectPoint.deviceId(), treatment, + ByteBuffer.wrap(probePacket.serialize())); + + packetService.emit(outboundPacket); + } + + private Ethernet buildArpRequest(IpAddress targetIp, IpAddress sourceIp, + MacAddress sourceMac, VlanId vlan) { + + ARP arp = new ARP(); + arp.setHardwareType(ARP.HW_TYPE_ETHERNET) + .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH) + .setProtocolType(ARP.PROTO_TYPE_IP) + .setProtocolAddressLength((byte) IpAddress.INET_BYTE_LENGTH) + .setOpCode(ARP.OP_REQUEST); + + arp.setSenderHardwareAddress(sourceMac.toBytes()) + .setSenderProtocolAddress(sourceIp.toOctets()) + .setTargetHardwareAddress(ZERO_MAC_ADDRESS) + .setTargetProtocolAddress(targetIp.toOctets()); + + Ethernet ethernet = new Ethernet(); + ethernet.setEtherType(Ethernet.TYPE_ARP) + .setDestinationMACAddress(MacAddress.BROADCAST) + .setSourceMACAddress(sourceMac) + .setPayload(arp); + + if (!vlan.equals(VlanId.NONE)) { + ethernet.setVlanID(vlan.toShort()); + } + + ethernet.setPad(true); + + return ethernet; + } + + private Ethernet buildNdpRequest(IpAddress targetIp, IpAddress sourceIp, + MacAddress sourceMac, VlanId vlan) { + + // Create the Ethernet packet + Ethernet ethernet = new Ethernet(); + ethernet.setEtherType(Ethernet.TYPE_IPV6) + .setDestinationMACAddress(MacAddress.BROADCAST) + .setSourceMACAddress(sourceMac); + if (!vlan.equals(VlanId.NONE)) { + ethernet.setVlanID(vlan.toShort()); + } + + // + // Create the IPv6 packet + // + // TODO: The destination IP address should be the + // solicited-node multicast address + IPv6 ipv6 = new IPv6(); + ipv6.setSourceAddress(sourceIp.toOctets()); + ipv6.setDestinationAddress(targetIp.toOctets()); + ipv6.setHopLimit((byte) 255); + + // Create the ICMPv6 packet + ICMP6 icmp6 = new ICMP6(); + icmp6.setIcmpType(ICMP6.NEIGHBOR_SOLICITATION); + icmp6.setIcmpCode((byte) 0); + + // Create the Neighbor Solication packet + NeighborSolicitation ns = new NeighborSolicitation(); + ns.setTargetAddress(targetIp.toOctets()); + ns.addOption(NeighborDiscoveryOptions.TYPE_SOURCE_LL_ADDRESS, + sourceMac.toBytes()); + + icmp6.setPayload(ns); + ipv6.setPayload(icmp6); + ethernet.setPayload(ipv6); + + return ethernet; + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/package-info.java new file mode 100644 index 00000000..1f7d5889 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/host/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Core subsystem for tracking global inventory of end-station hosts. + */ +package org.onosproject.net.host.impl; diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/CompilerRegistry.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/CompilerRegistry.java new file mode 100644 index 00000000..1b70bc67 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/CompilerRegistry.java @@ -0,0 +1,128 @@ +/* + * 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.intent.impl; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentCompiler; +import org.onosproject.net.intent.IntentException; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +// TODO: consider a better name +class CompilerRegistry { + + private final ConcurrentMap, + IntentCompiler> compilers = new ConcurrentHashMap<>(); + + /** + * Registers the specified compiler for the given intent class. + * + * @param cls intent class + * @param compiler intent compiler + * @param the type of intent + */ + public void registerCompiler(Class cls, IntentCompiler compiler) { + compilers.put(cls, compiler); + } + + /** + * Unregisters the compiler for the specified intent class. + * + * @param cls intent class + * @param the type of intent + */ + public void unregisterCompiler(Class cls) { + compilers.remove(cls); + } + + /** + * Returns immutable set of bindings of currently registered intent compilers. + * + * @return the set of compiler bindings + */ + public Map, IntentCompiler> getCompilers() { + return ImmutableMap.copyOf(compilers); + } + + /** + * Compiles an intent recursively. + * + * @param intent intent + * @param previousInstallables previous intent installables + * @return result of compilation + */ + List compile(Intent intent, List previousInstallables) { + if (intent.isInstallable()) { + return ImmutableList.of(intent); + } + + registerSubclassCompilerIfNeeded(intent); + // FIXME: get previous resources + List installable = new ArrayList<>(); + for (Intent compiled : getCompiler(intent).compile(intent, previousInstallables, null)) { + installable.addAll(compile(compiled, previousInstallables)); + } + return installable; + } + + /** + * Returns the corresponding intent compiler to the specified intent. + * + * @param intent intent + * @param the type of intent + * @return intent compiler corresponding to the specified intent + */ + private IntentCompiler getCompiler(T intent) { + @SuppressWarnings("unchecked") + IntentCompiler compiler = (IntentCompiler) compilers.get(intent.getClass()); + if (compiler == null) { + throw new IntentException("no compiler for class " + intent.getClass()); + } + return compiler; + } + + /** + * Registers an intent compiler of the specified intent if an intent compiler + * for the intent is not registered. This method traverses the class hierarchy of + * the intent. Once an intent compiler for a parent type is found, this method + * registers the found intent compiler. + * + * @param intent intent + */ + private void registerSubclassCompilerIfNeeded(Intent intent) { + if (!compilers.containsKey(intent.getClass())) { + Class cls = intent.getClass(); + while (cls != Object.class) { + // As long as we're within the Intent class descendants + if (Intent.class.isAssignableFrom(cls)) { + IntentCompiler compiler = compilers.get(cls); + if (compiler != null) { + compilers.put(intent.getClass(), compiler); + return; + } + } + cls = cls.getSuperclass(); + } + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentAccumulator.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentAccumulator.java new file mode 100644 index 00000000..54276ad4 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentAccumulator.java @@ -0,0 +1,82 @@ +/* + * 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.intent.impl; + +import com.google.common.collect.Maps; +import org.onlab.util.AbstractAccumulator; +import org.onosproject.net.intent.IntentBatchDelegate; +import org.onosproject.net.intent.IntentData; +import org.onosproject.net.intent.Key; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Timer; + +/** + * An accumulator for building batches of intent operations. Only one batch should + * be in process per instance at a time. + */ +public class IntentAccumulator extends AbstractAccumulator { + + private static final int DEFAULT_MAX_EVENTS = 1000; + private static final int DEFAULT_MAX_IDLE_MS = 10; + private static final int DEFAULT_MAX_BATCH_MS = 50; + + // FIXME: Replace with a system-wide timer instance; + // TODO: Convert to use HashedWheelTimer or produce a variant of that; then decide which we want to adopt + private static final Timer TIMER = new Timer("onos-intent-op-batching"); + + private final IntentBatchDelegate delegate; + + private volatile boolean ready; + + /** + * Creates an intent operation accumulator. + * + * @param delegate the intent batch delegate + */ + protected IntentAccumulator(IntentBatchDelegate delegate) { + super(TIMER, DEFAULT_MAX_EVENTS, DEFAULT_MAX_BATCH_MS, DEFAULT_MAX_IDLE_MS); + this.delegate = delegate; + // Assume that the delegate is ready for work at the start + ready = true; //TODO validate the assumption that delegate is ready + } + + @Override + public void processItems(List items) { + ready = false; + delegate.execute(reduce(items)); + } + + private Collection reduce(List ops) { + Map map = Maps.newHashMap(); + for (IntentData op : ops) { + map.put(op.key(), op); + } + //TODO check the version... or maybe store will handle this. + return map.values(); + } + + @Override + public boolean isReady() { + return ready; + } + + public void ready() { + ready = true; + } +} 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 new file mode 100644 index 00000000..d7fa3223 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java @@ -0,0 +1,254 @@ +/* + * 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.intent.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.Modified; +import org.apache.felix.scr.annotations.Property; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onosproject.cfg.ComponentConfigService; +import org.onosproject.net.intent.IntentData; +import org.onosproject.net.intent.IntentEvent; +import org.onosproject.net.intent.IntentListener; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.IntentStore; +import org.onosproject.net.intent.Key; +import org.osgi.service.component.ComponentContext; +import org.slf4j.Logger; + +import java.util.Dictionary; +import java.util.Properties; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ExecutorService; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static java.util.concurrent.Executors.newSingleThreadExecutor; +import static org.onlab.util.Tools.get; +import static org.onlab.util.Tools.groupedThreads; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * This component cleans up intents that have encountered errors or otherwise + * stalled during installation or withdrawal. + *

+ * It periodically polls (based on configured period) for pending and CORRUPT + * intents from the store and retries. It also listens for CORRUPT event + * notifications, which signify errors in processing, and retries. + *

+ */ +@Component(immediate = true) +public class IntentCleanup implements Runnable, IntentListener { + + private static final Logger log = getLogger(IntentCleanup.class); + + private static final int DEFAULT_PERIOD = 5; //seconds + private static final int DEFAULT_THRESHOLD = 5; //tries + + @Property(name = "enabled", boolValue = true, + label = "Enables/disables the intent cleanup component") + private boolean enabled = true; + + @Property(name = "period", intValue = DEFAULT_PERIOD, + label = "Frequency in ms between cleanup runs") + protected int period = DEFAULT_PERIOD; + private long periodMs; + + @Property(name = "retryThreshold", intValue = DEFAULT_THRESHOLD, + label = "Number of times to retry CORRUPT intent without delay") + protected int retryThreshold = DEFAULT_THRESHOLD; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentService service; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentStore store; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ComponentConfigService cfgService; + + private ExecutorService executor; + private Timer timer; + private TimerTask timerTask; + + @Activate + public void activate() { + cfgService.registerProperties(getClass()); + executor = newSingleThreadExecutor(groupedThreads("onos/intent", "cleanup")); + timer = new Timer("onos-intent-cleanup-timer"); + service.addListener(this); + adjustRate(); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + cfgService.unregisterProperties(getClass(), false); + service.removeListener(this); + timer.cancel(); + timerTask = null; + executor.shutdown(); + log.info("Stopped"); + } + + @Modified + public void modified(ComponentContext context) { + Dictionary properties = context != null ? context.getProperties() : new Properties(); + + int newPeriod; + boolean newEnabled; + try { + String s = get(properties, "period"); + newPeriod = isNullOrEmpty(s) ? period : Integer.parseInt(s.trim()); + + s = get(properties, "retryThreshold"); + retryThreshold = isNullOrEmpty(s) ? retryThreshold : Integer.parseInt(s.trim()); + + s = get(properties, "enabled"); + newEnabled = isNullOrEmpty(s) ? enabled : Boolean.parseBoolean(s.trim()); + } catch (NumberFormatException e) { + log.warn(e.getMessage()); + newPeriod = period; + newEnabled = enabled; + } + + // Any change in the following parameters implies hard restart + if (newPeriod != period || enabled != newEnabled) { + period = newPeriod; + enabled = newEnabled; + adjustRate(); + } + + log.info("Settings: enabled={}, period={}, retryThreshold={}", + enabled, period, retryThreshold); + } + + protected void adjustRate() { + if (timerTask != null) { + timerTask.cancel(); + timerTask = null; + } + + if (enabled) { + timerTask = new TimerTask() { + @Override + public void run() { + executor.submit(IntentCleanup.this); + } + }; + + periodMs = period * 1_000; //convert to ms + timer.scheduleAtFixedRate(timerTask, periodMs, periodMs); + } + } + + + @Override + public void run() { + try { + cleanup(); + } catch (Exception e) { + log.warn("Caught exception during Intent cleanup", e); + } + } + + private void resubmitCorrupt(IntentData intentData, boolean checkThreshold) { + if (checkThreshold && intentData.errorCount() >= retryThreshold) { + return; // threshold met or exceeded + } + + switch (intentData.request()) { + case INSTALL_REQ: + service.submit(intentData.intent()); + break; + case WITHDRAW_REQ: + service.withdraw(intentData.intent()); + break; + default: + log.warn("Trying to resubmit corrupt/failed intent {} in state {} with request {}", + intentData.key(), intentData.state(), intentData.request()); + break; + } + } + + private void resubmitPendingRequest(IntentData intentData) { + switch (intentData.request()) { + case INSTALL_REQ: + service.submit(intentData.intent()); + break; + case WITHDRAW_REQ: + service.withdraw(intentData.intent()); + break; + default: + log.warn("Trying to resubmit pending intent {} in state {} with request {}", + intentData.key(), intentData.state(), intentData.request()); + break; + } + } + + /** + * Iterates through corrupt, failed and pending intents and + * re-submit/withdraw appropriately. + */ + private void cleanup() { + int corruptCount = 0, failedCount = 0, stuckCount = 0, pendingCount = 0; + + for (IntentData intentData : store.getIntentData(true, periodMs)) { + switch (intentData.state()) { + case FAILED: + resubmitCorrupt(intentData, false); + failedCount++; + break; + case CORRUPT: + resubmitCorrupt(intentData, false); + corruptCount++; + break; + case INSTALLING: //FALLTHROUGH + case WITHDRAWING: + resubmitPendingRequest(intentData); + stuckCount++; + break; + default: + //NOOP + break; + } + } + + for (IntentData intentData : store.getPendingData(true, periodMs)) { + resubmitPendingRequest(intentData); + stuckCount++; + } + + log.debug("Intent cleanup ran and resubmitted {} corrupt, {} failed, {} stuck, and {} pending intents", + corruptCount, failedCount, stuckCount, pendingCount); + } + + @Override + public void event(IntentEvent event) { + // this is the fast path for CORRUPT intents, retry on event notification. + //TODO we might consider using the timer to back off for subsequent retries + if (enabled && event.type() == IntentEvent.Type.CORRUPT) { + Key key = event.subject().key(); + if (store.isMaster(key)) { + IntentData data = store.getIntentData(event.subject().key()); + resubmitCorrupt(data, true); + } + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCompilationException.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCompilationException.java new file mode 100644 index 00000000..ae93336c --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCompilationException.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 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.intent.impl; + +import org.onosproject.net.intent.IntentException; + +/** + * An exception thrown when a intent compilation fails. + */ +public class IntentCompilationException extends IntentException { + private static final long serialVersionUID = 235237603018210810L; + + public IntentCompilationException() { + super(); + } + + public IntentCompilationException(String message) { + super(message); + } + + public IntentCompilationException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentInstallationException.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentInstallationException.java new file mode 100644 index 00000000..db21fe4a --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentInstallationException.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 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.intent.impl; + +import org.onosproject.net.intent.IntentException; + +/** + * An exception thrown when intent installation fails. + */ +public class IntentInstallationException extends IntentException { + private static final long serialVersionUID = 3720268258616014168L; + + public IntentInstallationException() { + super(); + } + + public IntentInstallationException(String message) { + super(message); + } + + public IntentInstallationException(String message, Throwable cause) { + super(message, cause); + } +} 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 new file mode 100644 index 00000000..4c828e77 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentManager.java @@ -0,0 +1,488 @@ +/* + * Copyright 2014-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.intent.impl; + +import com.google.common.collect.ImmutableList; +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.event.AbstractListenerManager; +import org.onosproject.core.CoreService; +import org.onosproject.core.IdGenerator; +import org.onosproject.net.flow.FlowRule; +import org.onosproject.net.flow.FlowRuleOperations; +import org.onosproject.net.flow.FlowRuleOperationsContext; +import org.onosproject.net.flow.FlowRuleService; +import org.onosproject.net.intent.FlowRuleIntent; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentBatchDelegate; +import org.onosproject.net.intent.IntentCompiler; +import org.onosproject.net.intent.IntentData; +import org.onosproject.net.intent.IntentEvent; +import org.onosproject.net.intent.IntentExtensionService; +import org.onosproject.net.intent.IntentListener; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.IntentState; +import org.onosproject.net.intent.IntentStore; +import org.onosproject.net.intent.IntentStoreDelegate; +import org.onosproject.net.intent.Key; +import org.onosproject.net.intent.impl.phase.FinalIntentProcessPhase; +import org.onosproject.net.intent.impl.phase.IntentProcessPhase; +import org.onosproject.net.intent.impl.phase.IntentWorker; +import org.slf4j.Logger; + +import java.util.Collection; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.concurrent.Executors.newFixedThreadPool; +import static java.util.concurrent.Executors.newSingleThreadExecutor; +import static org.onlab.util.Tools.groupedThreads; +import static org.onosproject.net.intent.IntentState.*; +import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure; +import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.slf4j.LoggerFactory.getLogger; +import static org.onosproject.security.AppPermission.Type.*; + + +/** + * An implementation of intent service. + */ +@Component(immediate = true) +@Service +public class IntentManager + extends AbstractListenerManager + implements IntentService, IntentExtensionService { + + private static final Logger log = getLogger(IntentManager.class); + + public static final String INTENT_NULL = "Intent cannot be null"; + public static final String INTENT_ID_NULL = "Intent key cannot be null"; + + private static final int NUM_THREADS = 12; + + private static final EnumSet RECOMPILE + = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ); + private static final EnumSet WITHDRAW + = EnumSet.of(WITHDRAW_REQ, WITHDRAWING, WITHDRAWN); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentStore store; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ObjectiveTrackerService trackerService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected FlowRuleService flowRuleService; + + private ExecutorService batchExecutor; + private ExecutorService workerExecutor; + + private final CompilerRegistry compilerRegistry = new CompilerRegistry(); + private final InternalIntentProcessor processor = new InternalIntentProcessor(); + private final IntentStoreDelegate delegate = new InternalStoreDelegate(); + private final TopologyChangeDelegate topoDelegate = new InternalTopoChangeDelegate(); + private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate(); + private IdGenerator idGenerator; + + private final IntentAccumulator accumulator = new IntentAccumulator(batchDelegate); + + @Activate + public void activate() { + store.setDelegate(delegate); + trackerService.setDelegate(topoDelegate); + eventDispatcher.addSink(IntentEvent.class, listenerRegistry); + batchExecutor = newSingleThreadExecutor(groupedThreads("onos/intent", "batch")); + workerExecutor = newFixedThreadPool(NUM_THREADS, groupedThreads("onos/intent", "worker-%d")); + idGenerator = coreService.getIdGenerator("intent-ids"); + Intent.bindIdGenerator(idGenerator); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + store.unsetDelegate(delegate); + trackerService.unsetDelegate(topoDelegate); + eventDispatcher.removeSink(IntentEvent.class); + batchExecutor.shutdown(); + workerExecutor.shutdown(); + Intent.unbindIdGenerator(idGenerator); + log.info("Stopped"); + } + + @Override + public void submit(Intent intent) { + checkPermission(INTENT_WRITE); + checkNotNull(intent, INTENT_NULL); + IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null); + store.addPending(data); + } + + @Override + public void withdraw(Intent intent) { + checkPermission(INTENT_WRITE); + checkNotNull(intent, INTENT_NULL); + IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null); + store.addPending(data); + } + + @Override + public void purge(Intent intent) { + checkPermission(INTENT_WRITE); + checkNotNull(intent, INTENT_NULL); + IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null); + store.addPending(data); + } + + @Override + public Intent getIntent(Key key) { + checkPermission(INTENT_READ); + return store.getIntent(key); + } + + @Override + public Iterable getIntents() { + checkPermission(INTENT_READ); + return store.getIntents(); + } + + @Override + public Iterable getIntentData() { + checkPermission(INTENT_READ); + return store.getIntentData(false, 0); + } + + @Override + public long getIntentCount() { + checkPermission(INTENT_READ); + return store.getIntentCount(); + } + + @Override + public IntentState getIntentState(Key intentKey) { + checkPermission(INTENT_READ); + checkNotNull(intentKey, INTENT_ID_NULL); + return store.getIntentState(intentKey); + } + + @Override + public List getInstallableIntents(Key intentKey) { + checkPermission(INTENT_READ); + checkNotNull(intentKey, INTENT_ID_NULL); + return store.getInstallableIntents(intentKey); + } + + @Override + public boolean isLocal(Key intentKey) { + checkPermission(INTENT_READ); + return store.isMaster(intentKey); + } + + @Override + public void registerCompiler(Class cls, IntentCompiler compiler) { + compilerRegistry.registerCompiler(cls, compiler); + } + + @Override + public void unregisterCompiler(Class cls) { + compilerRegistry.unregisterCompiler(cls); + } + + @Override + public Map, IntentCompiler> getCompilers() { + return compilerRegistry.getCompilers(); + } + + @Override + public Iterable getPending() { + checkPermission(INTENT_READ); + + return store.getPending(); + } + + // Store delegate to re-post events emitted from the store. + private class InternalStoreDelegate implements IntentStoreDelegate { + @Override + public void notify(IntentEvent event) { + post(event); + } + + @Override + public void process(IntentData data) { + accumulator.add(data); + } + + @Override + public void onUpdate(IntentData intentData) { + trackerService.trackIntent(intentData); + } + } + + private void buildAndSubmitBatches(Iterable intentKeys, + boolean compileAllFailed) { + // Attempt recompilation of the specified intents first. + for (Key key : intentKeys) { + Intent intent = store.getIntent(key); + if (intent == null) { + continue; + } + 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); + } + } + } + + //FIXME +// for (ApplicationId appId : batches.keySet()) { +// if (batchService.isLocalLeader(appId)) { +// execute(batches.get(appId).build()); +// } +// } + } + + // Topology change delegate + private class InternalTopoChangeDelegate implements TopologyChangeDelegate { + @Override + public void triggerCompile(Iterable intentKeys, + boolean compileAllFailed) { + buildAndSubmitBatches(intentKeys, compileAllFailed); + } + } + + private Future submitIntentData(IntentData data) { + IntentData current = store.getIntentData(data.key()); + IntentProcessPhase initial = newInitialPhase(processor, data, current); + return workerExecutor.submit(new IntentWorker(initial)); + } + + private class IntentBatchProcess implements Runnable { + + protected final Collection data; + + IntentBatchProcess(Collection data) { + this.data = checkNotNull(data); + } + + @Override + public void run() { + try { + /* + 1. wrap each intentdata in a runnable and submit + 2. wait for completion of all the work + 3. accumulate results and submit batch write of IntentData to store + (we can also try to update these individually) + */ + submitUpdates(waitForFutures(createIntentUpdates())); + } catch (Exception e) { + log.error("Error submitting batches:", e); + // FIXME incomplete Intents should be cleaned up + // (transition to FAILED, etc.) + + // the batch has failed + // TODO: maybe we should do more? + log.error("Walk the plank, matey..."); + //FIXME +// batchService.removeIntentOperations(data); + } + accumulator.ready(); + } + + private List> createIntentUpdates() { + return data.stream() + .map(IntentManager.this::submitIntentData) + .collect(Collectors.toList()); + } + + private List waitForFutures(List> futures) { + ImmutableList.Builder updateBuilder = ImmutableList.builder(); + for (Future future : futures) { + try { + updateBuilder.add(future.get()); + } catch (InterruptedException | ExecutionException e) { + //FIXME + log.warn("Future failed: {}", e); + } + } + return updateBuilder.build(); + } + + private void submitUpdates(List updates) { + store.batchWrite(updates.stream() + .map(FinalIntentProcessPhase::data) + .collect(Collectors.toList())); + } + } + + private class InternalBatchDelegate implements IntentBatchDelegate { + @Override + public void execute(Collection operations) { + log.debug("Execute {} operation(s).", operations.size()); + log.trace("Execute operations: {}", operations); + + // batchExecutor is single-threaded, so only one batch is in flight at a time + batchExecutor.execute(new IntentBatchProcess(operations)); + } + } + + private class InternalIntentProcessor implements IntentProcessor { + @Override + public List compile(Intent intent, List previousInstallables) { + return compilerRegistry.compile(intent, previousInstallables); + } + + @Override + public void apply(Optional toUninstall, Optional toInstall) { + IntentManager.this.apply(toUninstall, toInstall); + } + } + + private enum Direction { + ADD, + REMOVE + } + + private void applyIntentData(Optional intentData, + FlowRuleOperations.Builder builder, + Direction direction) { + if (!intentData.isPresent()) { + return; + } + IntentData data = intentData.get(); + + List intentsToApply = data.installables(); + if (!intentsToApply.stream().allMatch(x -> x instanceof FlowRuleIntent)) { + throw new IllegalStateException("installable intents must be FlowRuleIntent"); + } + + if (direction == Direction.ADD) { + trackerService.addTrackedResources(data.key(), data.intent().resources()); + intentsToApply.forEach(installable -> + trackerService.addTrackedResources(data.key(), installable.resources())); + } else { + trackerService.removeTrackedResources(data.key(), data.intent().resources()); + intentsToApply.forEach(installable -> + trackerService.removeTrackedResources(data.intent().key(), + installable.resources())); + } + + // FIXME do FlowRuleIntents have stages??? Can we do uninstall work in parallel? I think so. + builder.newStage(); + + List> stages = intentsToApply.stream() + .map(x -> (FlowRuleIntent) x) + .map(FlowRuleIntent::flowRules) + .collect(Collectors.toList()); + + for (Collection rules : stages) { + if (direction == Direction.ADD) { + rules.forEach(builder::add); + } else { + rules.forEach(builder::remove); + } + } + + } + + private void apply(Optional toUninstall, Optional toInstall) { + // need to consider if FlowRuleIntent is only one as installable intent or not + + FlowRuleOperations.Builder builder = FlowRuleOperations.builder(); + applyIntentData(toUninstall, builder, Direction.REMOVE); + applyIntentData(toInstall, builder, Direction.ADD); + + FlowRuleOperations operations = builder.build(new FlowRuleOperationsContext() { + @Override + public void onSuccess(FlowRuleOperations ops) { + if (toInstall.isPresent()) { + IntentData installData = toInstall.get(); + log.debug("Completed installing: {}", installData.key()); + installData.setState(INSTALLED); + store.write(installData); + } else if (toUninstall.isPresent()) { + IntentData uninstallData = toUninstall.get(); + log.debug("Completed withdrawing: {}", uninstallData.key()); + switch (uninstallData.request()) { + case INSTALL_REQ: + uninstallData.setState(FAILED); + break; + case WITHDRAW_REQ: + default: //TODO "default" case should not happen + uninstallData.setState(WITHDRAWN); + break; + } + store.write(uninstallData); + } + } + + @Override + public void onError(FlowRuleOperations ops) { + // if toInstall was cause of error, then recompile (manage/increment counter, when exceeded -> CORRUPT) + if (toInstall.isPresent()) { + IntentData installData = toInstall.get(); + log.warn("Failed installation: {} {} on {}", + installData.key(), installData.intent(), ops); + installData.setState(CORRUPT); + installData.incrementErrorCount(); + store.write(installData); + } + // if toUninstall was cause of error, then CORRUPT (another job will clean this up) + if (toUninstall.isPresent()) { + IntentData uninstallData = toUninstall.get(); + log.warn("Failed withdrawal: {} {} on {}", + uninstallData.key(), uninstallData.intent(), ops); + uninstallData.setState(CORRUPT); + uninstallData.incrementErrorCount(); + store.write(uninstallData); + } + } + }); + + if (log.isTraceEnabled()) { + log.trace("applying intent {} -> {} with {} rules: {}", + toUninstall.isPresent() ? toUninstall.get().key() : "", + toInstall.isPresent() ? toInstall.get().key() : "", + operations.stages().stream().mapToLong(i -> i.size()).sum(), + operations.stages()); + } + + flowRuleService.apply(operations); + } + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentProcessor.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentProcessor.java new file mode 100644 index 00000000..5469c766 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentProcessor.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.net.intent.impl; + +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentData; + +import java.util.List; +import java.util.Optional; + +/** + * A collection of methods to process an intent. + * + * This interface is public, but intended to be used only by IntentManager and + * IntentProcessPhase subclasses stored under phase package. + */ +public interface IntentProcessor { + + /** + * Compiles an intent recursively. + * + * @param intent intent + * @param previousInstallables previous intent installables + * @return result of compilation + */ + List compile(Intent intent, List previousInstallables); + + /** + * @param toUninstall Intent data describing flows to uninstall. + * @param toInstall Intent data describing flows to install. + */ + void apply(Optional toUninstall, Optional toInstall); +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentRemovalException.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentRemovalException.java new file mode 100644 index 00000000..20530c0c --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/IntentRemovalException.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 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.intent.impl; + +import org.onosproject.net.intent.IntentException; + +/** + * An exception thrown when intent removal failed. + */ +public class IntentRemovalException extends IntentException { + private static final long serialVersionUID = -5259226322037891951L; + + public IntentRemovalException() { + super(); + } + + public IntentRemovalException(String message) { + super(message); + } + + public IntentRemovalException(String message, Throwable cause) { + super(message, cause); + } +} 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 new file mode 100644 index 00000000..5710aced --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTracker.java @@ -0,0 +1,457 @@ +/* + * Copyright 2014-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.intent.impl; + +import com.google.common.collect.HashMultimap; +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; +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.ReferencePolicy; +import org.apache.felix.scr.annotations.Service; +import org.onosproject.core.ApplicationId; +import org.onosproject.event.Event; +import org.onosproject.net.DeviceId; +import org.onosproject.net.ElementId; +import org.onosproject.net.HostId; +import org.onosproject.net.Link; +import org.onosproject.net.LinkKey; +import org.onosproject.net.NetworkResource; +import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceListener; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.host.HostEvent; +import org.onosproject.net.host.HostListener; +import org.onosproject.net.host.HostService; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentData; +import org.onosproject.net.intent.IntentService; +import org.onosproject.net.intent.Key; +import org.onosproject.net.intent.PartitionEvent; +import org.onosproject.net.intent.PartitionEventListener; +import org.onosproject.net.intent.PartitionService; +import org.onosproject.net.link.LinkEvent; +import org.onosproject.net.resource.link.LinkResourceEvent; +import org.onosproject.net.resource.link.LinkResourceListener; +import org.onosproject.net.resource.link.LinkResourceService; +import org.onosproject.net.topology.TopologyEvent; +import org.onosproject.net.topology.TopologyListener; +import org.onosproject.net.topology.TopologyService; +import org.slf4j.Logger; + +import java.util.Collection; +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; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Multimaps.synchronizedSetMultimap; +import static java.util.concurrent.Executors.newSingleThreadExecutor; +import static org.onlab.util.Tools.groupedThreads; +import static org.onlab.util.Tools.isNullOrEmpty; +import static org.onosproject.net.LinkKey.linkKey; +import static org.onosproject.net.intent.IntentState.INSTALLED; +import static org.onosproject.net.intent.IntentState.INSTALLING; +import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED; +import static org.onosproject.net.link.LinkEvent.Type.LINK_UPDATED; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Entity responsible for tracking installed flows and for monitoring topology + * events to determine what flows are affected by topology changes. + */ +@Component(immediate = true) +@Service +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()); + + private final SetMultimap intentsByDevice = + synchronizedSetMultimap(HashMultimap.create()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected TopologyService topologyService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LinkResourceService resourceManager; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected HostService hostService; + + @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY, + policy = ReferencePolicy.DYNAMIC) + protected IntentService intentService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected PartitionService partitionService; + + private ExecutorService executorService = + newSingleThreadExecutor(groupedThreads("onos/intent", "objectivetracker")); + private ScheduledExecutorService executor = Executors + .newScheduledThreadPool(1); + + private TopologyListener listener = new InternalTopologyListener(); + private LinkResourceListener linkResourceListener = + new InternalLinkResourceListener(); + private DeviceListener deviceListener = new InternalDeviceListener(); + private HostListener hostListener = new InternalHostListener(); + private PartitionEventListener partitionListener = new InternalPartitionListener(); + private TopologyChangeDelegate delegate; + + protected final AtomicBoolean updateScheduled = new AtomicBoolean(false); + + @Activate + public void activate() { + topologyService.addListener(listener); + resourceManager.addListener(linkResourceListener); + deviceService.addListener(deviceListener); + hostService.addListener(hostListener); + partitionService.addListener(partitionListener); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + topologyService.removeListener(listener); + resourceManager.removeListener(linkResourceListener); + deviceService.removeListener(deviceListener); + hostService.removeListener(hostListener); + partitionService.removeListener(partitionListener); + log.info("Stopped"); + } + + protected void bindIntentService(IntentService service) { + if (intentService == null) { + intentService = service; + } + } + + protected void unbindIntentService(IntentService service) { + if (intentService == service) { + intentService = null; + } + } + + @Override + public void setDelegate(TopologyChangeDelegate delegate) { + checkNotNull(delegate, "Delegate cannot be null"); + checkArgument(this.delegate == null || this.delegate == delegate, + "Another delegate already set"); + this.delegate = delegate; + } + + @Override + public void unsetDelegate(TopologyChangeDelegate delegate) { + checkArgument(this.delegate == delegate, "Not the current delegate"); + this.delegate = null; + } + + @Override + public void addTrackedResources(Key intentKey, + Collection resources) { + for (NetworkResource resource : resources) { + if (resource instanceof Link) { + intentsByLink.put(linkKey((Link) resource), intentKey); + } else if (resource instanceof ElementId) { + intentsByDevice.put((ElementId) resource, intentKey); + } + } + } + + @Override + public void removeTrackedResources(Key intentKey, + Collection resources) { + for (NetworkResource resource : resources) { + if (resource instanceof Link) { + intentsByLink.remove(linkKey((Link) resource), intentKey); + } else if (resource instanceof ElementId) { + intentsByDevice.remove(resource, intentKey); + } + } + } + + @Override + public void trackIntent(IntentData intentData) { + + //NOTE: This will be called for intents that are being added to the store + // locally (i.e. every intent update) + + Key key = intentData.key(); + Intent intent = intentData.intent(); + boolean isLocal = intentService.isLocal(key); + boolean isInstalled = intentData.state() == INSTALLING || + intentData.state() == INSTALLED; + List installables = intentData.installables(); + + if (log.isTraceEnabled()) { + log.trace("intent {}, old: {}, new: {}, installableCount: {}, resourceCount: {}", + key, + intentsByDevice.values().contains(key), + isLocal && isInstalled, + installables.size(), + intent.resources().size() + + installables.stream() + .mapToLong(i -> i.resources().size()).sum()); + } + + if (isNullOrEmpty(installables) && intentData.state() == INSTALLED) { + log.warn("Intent {} is INSTALLED with no installables", key); + } + + // FIXME Intents will be added 3 times (once directly using addTracked, + // then when installing and when installed) + if (isLocal && isInstalled) { + addTrackedResources(key, intent.resources()); + for (Intent installable : installables) { + addTrackedResources(key, installable.resources()); + } + // FIXME check all resources against current topo service(s); recompile if necessary + } else { + removeTrackedResources(key, intent.resources()); + for (Intent installable : installables) { + removeTrackedResources(key, installable.resources()); + } + } + } + + // Internal re-actor to topology change events. + private class InternalTopologyListener implements TopologyListener { + @Override + public void event(TopologyEvent event) { + executorService.execute(new TopologyChangeHandler(event)); + } + } + + // Re-dispatcher of topology change events. + private class TopologyChangeHandler implements Runnable { + + private final TopologyEvent event; + + TopologyChangeHandler(TopologyEvent event) { + this.event = event; + } + + @Override + public void run() { + // If there is no delegate, why bother? Just bail. + if (delegate == null) { + return; + } + + if (event.reasons() == null || event.reasons().isEmpty()) { + delegate.triggerCompile(Collections.emptySet(), true); + + } else { + Set intentsToRecompile = new HashSet<>(); + boolean dontRecompileAllFailedIntents = true; + + // Scan through the list of reasons and keep accruing all + // intents that need to be recompiled. + for (Event reason : event.reasons()) { + if (reason instanceof LinkEvent) { + LinkEvent linkEvent = (LinkEvent) reason; + final LinkKey linkKey = linkKey(linkEvent.subject()); + synchronized (intentsByLink) { + Set intentKeys = intentsByLink.get(linkKey); + log.debug("recompile triggered by LinkEvent {} ({}) for {}", + linkKey, linkEvent.type(), intentKeys); + intentsToRecompile.addAll(intentKeys); + } + dontRecompileAllFailedIntents = dontRecompileAllFailedIntents && + (linkEvent.type() == LINK_REMOVED || + (linkEvent.type() == LINK_UPDATED && + linkEvent.subject().isDurable())); + } + } + delegate.triggerCompile(intentsToRecompile, !dontRecompileAllFailedIntents); + } + } + } + + /** + * Internal re-actor to resource available events. + */ + private class InternalLinkResourceListener implements LinkResourceListener { + @Override + public void event(LinkResourceEvent event) { + executorService.execute(new ResourceAvailableHandler(event)); + } + } + + /* + * Re-dispatcher of resource available events. + */ + private class ResourceAvailableHandler implements Runnable { + + private final LinkResourceEvent event; + + ResourceAvailableHandler(LinkResourceEvent event) { + this.event = event; + } + + @Override + public void run() { + // If there is no delegate, why bother? Just bail. + if (delegate == null) { + return; + } + + delegate.triggerCompile(Collections.emptySet(), true); + } + } + + //TODO consider adding flow rule event tracking + + private void updateTrackedResources(ApplicationId appId, boolean track) { + if (intentService == null) { + log.warn("Intent service is not bound yet"); + return; + } + intentService.getIntents().forEach(intent -> { + if (intent.appId().equals(appId)) { + Key key = intent.key(); + Collection resources = Lists.newArrayList(); + intentService.getInstallableIntents(key).stream() + .map(installable -> installable.resources()) + .forEach(resources::addAll); + if (track) { + addTrackedResources(key, resources); + } else { + removeTrackedResources(key, resources); + } + } + }); + } + + /* + * Re-dispatcher of device and host events. + */ + private class DeviceAvailabilityHandler implements Runnable { + + private final ElementId id; + private final boolean available; + + DeviceAvailabilityHandler(ElementId id, boolean available) { + this.id = checkNotNull(id); + this.available = available; + } + + @Override + public void run() { + // If there is no delegate, why bother? Just bail. + if (delegate == null) { + return; + } + + // TODO should we recompile on available==true? + delegate.triggerCompile(intentsByDevice.get(id), available); + } + } + + + private class InternalDeviceListener implements DeviceListener { + @Override + public void event(DeviceEvent event) { + DeviceEvent.Type type = event.type(); + switch (type) { + case DEVICE_ADDED: + case DEVICE_AVAILABILITY_CHANGED: + case DEVICE_REMOVED: + case DEVICE_SUSPENDED: + case DEVICE_UPDATED: + DeviceId id = event.subject().id(); + // TODO we need to check whether AVAILABILITY_CHANGED means up or down + boolean available = (type == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED || + type == DeviceEvent.Type.DEVICE_ADDED || + type == DeviceEvent.Type.DEVICE_UPDATED); + executorService.execute(new DeviceAvailabilityHandler(id, available)); + break; + case PORT_ADDED: + case PORT_REMOVED: + case PORT_UPDATED: + case PORT_STATS_UPDATED: + default: + // Don't handle port events for now + break; + } + } + } + + private class InternalHostListener implements HostListener { + @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)); + } + } + + protected void doIntentUpdate() { + updateScheduled.set(false); + if (intentService == null) { + log.warn("Intent service is not bound yet"); + return; + } + try { + //FIXME very inefficient + for (IntentData intentData : intentService.getIntentData()) { + try { + trackIntent(intentData); + } catch (NullPointerException npe) { + log.warn("intent error {}", intentData.key(), npe); + } + } + } catch (Exception e) { + log.warn("Exception caught during update task", e); + } + } + + private void scheduleIntentUpdate(int afterDelaySec) { + if (updateScheduled.compareAndSet(false, true)) { + executor.schedule(this::doIntentUpdate, afterDelaySec, TimeUnit.SECONDS); + } + } + + private final class InternalPartitionListener implements PartitionEventListener { + @Override + public void event(PartitionEvent event) { + log.debug("got message {}", event.subject()); + scheduleIntentUpdate(1); + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTrackerService.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTrackerService.java new file mode 100644 index 00000000..b7d367d7 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/ObjectiveTrackerService.java @@ -0,0 +1,69 @@ +/* + * Copyright 2014-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.intent.impl; + +import org.onosproject.net.NetworkResource; +import org.onosproject.net.intent.IntentData; +import org.onosproject.net.intent.Key; + +import java.util.Collection; + +/** + * Auxiliary service for tracking intent path flows and for notifying the + * intent service of environment changes via topology change delegate. + */ +public interface ObjectiveTrackerService { + + /** + * Sets a topology change delegate. + * + * @param delegate topology change delegate + */ + void setDelegate(TopologyChangeDelegate delegate); + + /** + * Unsets topology change delegate. + * + * @param delegate topology change delegate + */ + void unsetDelegate(TopologyChangeDelegate delegate); + + /** + * Adds a path flow to be tracked. + * + * @param intentKey intent identity on whose behalf the path is being tracked + * @param resources resources to track + */ + // TODO consider using the IntentData here rather than just the key + void addTrackedResources(Key intentKey, + Collection resources); + + /** + * Removes a path flow to be tracked. + * + * @param intentKey intent identity on whose behalf the path is being tracked + * @param resources resources to stop tracking + */ + void removeTrackedResources(Key intentKey, + Collection resources); + + /** + * Submits the specified intent data to be tracked. + * + * @param intentData intent data object to be tracked + */ + void trackIntent(IntentData intentData); +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/PathNotFoundException.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/PathNotFoundException.java new file mode 100644 index 00000000..c06e9fd2 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/PathNotFoundException.java @@ -0,0 +1,46 @@ +/* + * Copyright 2014-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.intent.impl; + +import com.google.common.base.MoreObjects; +import org.onosproject.net.ElementId; +import org.onosproject.net.intent.IntentException; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An exception thrown when a path is not found. + */ +public class PathNotFoundException extends IntentException { + private static final long serialVersionUID = -2087045731049914733L; + + private final ElementId source; + private final ElementId destination; + + public PathNotFoundException(ElementId source, ElementId destination) { + super(String.format("No path from %s to %s", source, destination)); + this.source = checkNotNull(source); + this.destination = checkNotNull(destination); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("source", source) + .add("destination", destination) + .toString(); + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/TopologyChangeDelegate.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/TopologyChangeDelegate.java new file mode 100644 index 00000000..49b114d5 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/TopologyChangeDelegate.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014-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.intent.impl; + +import org.onosproject.net.intent.Key; + +/** + * Auxiliary delegate for integration of intent manager and flow trackerService. + */ +public interface TopologyChangeDelegate { + + /** + * Notifies that topology has changed in such a way that the specified + * intents should be recompiled. If the {@code compileAllFailed} parameter + * is true, then all intents in {@link org.onosproject.net.intent.IntentState#FAILED} + * state should be compiled as well. + * + * @param intentIds intents that should be recompiled + * @param compileAllFailed true implies full compile of all failed intents + * is required; false for selective recompile only + */ + void triggerCompile(Iterable intentIds, boolean compileAllFailed); + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/ConnectivityIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/ConnectivityIntentCompiler.java new file mode 100644 index 00000000..6de4cfdc --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/ConnectivityIntentCompiler.java @@ -0,0 +1,152 @@ +/* + * Copyright 2014-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.intent.impl.compiler; + +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onosproject.net.ElementId; +import org.onosproject.net.Path; +import org.onosproject.net.intent.ConnectivityIntent; +import org.onosproject.net.intent.Constraint; +import org.onosproject.net.intent.IntentCompiler; +import org.onosproject.net.intent.IntentExtensionService; +import org.onosproject.net.intent.impl.PathNotFoundException; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.net.resource.link.LinkResourceService; +import org.onosproject.net.topology.LinkWeight; +import org.onosproject.net.topology.PathService; +import org.onosproject.net.topology.TopologyEdge; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * Base class for compilers of various + * {@link org.onosproject.net.intent.ConnectivityIntent connectivity intents}. + */ +@Component(immediate = true) +public abstract class ConnectivityIntentCompiler + implements IntentCompiler { + + private static final ProviderId PID = new ProviderId("core", "org.onosproject.core", true); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentExtensionService intentManager; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected PathService pathService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LinkResourceService resourceService; + + /** + * Returns an edge-weight capable of evaluating links on the basis of the + * specified constraints. + * + * @param constraints path constraints + * @return edge-weight function + */ + protected LinkWeight weight(List constraints) { + return new ConstraintBasedLinkWeight(constraints); + } + + /** + * Validates the specified path against the given constraints. + * + * @param path path to be checked + * @param constraints path constraints + * @return true if the path passes all constraints + */ + protected boolean checkPath(Path path, List constraints) { + for (Constraint constraint : constraints) { + if (!constraint.validate(path, resourceService)) { + return false; + } + } + return true; + } + + /** + * Computes a path between two ConnectPoints. + * + * @param intent intent on which behalf path is being computed + * @param one start of the path + * @param two end of the path + * @return Path between the two + * @throws PathNotFoundException if a path cannot be found + */ + protected Path getPath(ConnectivityIntent intent, + ElementId one, ElementId two) { + Set paths = pathService.getPaths(one, two, weight(intent.constraints())); + final List constraints = intent.constraints(); + ImmutableList filtered = FluentIterable.from(paths) + .filter(path -> checkPath(path, constraints)) + .toList(); + if (filtered.isEmpty()) { + throw new PathNotFoundException(one, two); + } + // TODO: let's be more intelligent about this eventually + return filtered.iterator().next(); + } + + /** + * Edge-weight capable of evaluating link cost using a set of constraints. + */ + protected class ConstraintBasedLinkWeight implements LinkWeight { + + private final List constraints; + + /** + * Creates a new edge-weight function capable of evaluating links + * on the basis of the specified constraints. + * + * @param constraints path constraints + */ + ConstraintBasedLinkWeight(List constraints) { + if (constraints == null) { + this.constraints = Collections.emptyList(); + } else { + this.constraints = ImmutableList.copyOf(constraints); + } + } + + @Override + public double weight(TopologyEdge edge) { + if (!constraints.iterator().hasNext()) { + return 1.0; + } + + // iterate over all constraints in order and return the weight of + // the first one with fast fail over the first failure + Iterator it = constraints.iterator(); + + double cost = it.next().cost(edge.link(), resourceService); + while (it.hasNext() && cost > 0) { + if (it.next().cost(edge.link(), resourceService) < 0) { + return -1; + } + } + return cost; + + } + } + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/HostToHostIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/HostToHostIntentCompiler.java new file mode 100644 index 00000000..41168258 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/HostToHostIntentCompiler.java @@ -0,0 +1,110 @@ +/* + * Copyright 2014-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.intent.impl.compiler; + +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.onosproject.net.DefaultLink; +import org.onosproject.net.DefaultPath; +import org.onosproject.net.Host; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.host.HostService; +import org.onosproject.net.intent.HostToHostIntent; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.PathIntent; +import org.onosproject.net.intent.constraint.AsymmetricPathConstraint; +import org.onosproject.net.resource.link.LinkResourceAllocations; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +import static org.onosproject.net.flow.DefaultTrafficSelector.builder; + +/** + * A intent compiler for {@link HostToHostIntent}. + */ +@Component(immediate = true) +public class HostToHostIntentCompiler + extends ConnectivityIntentCompiler { + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected HostService hostService; + + @Activate + public void activate() { + intentManager.registerCompiler(HostToHostIntent.class, this); + } + + @Deactivate + public void deactivate() { + intentManager.unregisterCompiler(HostToHostIntent.class); + } + + @Override + public List compile(HostToHostIntent intent, List installable, + Set resources) { + boolean isAsymmetric = intent.constraints().contains(new AsymmetricPathConstraint()); + Path pathOne = getPath(intent, intent.one(), intent.two()); + Path pathTwo = isAsymmetric ? + getPath(intent, intent.two(), intent.one()) : invertPath(pathOne); + + Host one = hostService.getHost(intent.one()); + Host two = hostService.getHost(intent.two()); + + return Arrays.asList(createPathIntent(pathOne, one, two, intent), + createPathIntent(pathTwo, two, one, intent)); + } + + // Inverts the specified path. This makes an assumption that each link in + // the path has a reverse link available. Under most circumstances, this + // assumption will hold. + private Path invertPath(Path path) { + List reverseLinks = new ArrayList<>(path.links().size()); + for (Link link : path.links()) { + reverseLinks.add(0, reverseLink(link)); + } + return new DefaultPath(path.providerId(), reverseLinks, path.cost()); + } + + // Produces a reverse variant of the specified link. + private Link reverseLink(Link link) { + return new DefaultLink(link.providerId(), link.dst(), link.src(), + link.type(), link.state(), link.isDurable()); + } + + // Creates a path intent from the specified path and original connectivity intent. + private Intent createPathIntent(Path path, Host src, Host dst, + HostToHostIntent intent) { + TrafficSelector selector = builder(intent.selector()) + .matchEthSrc(src.mac()).matchEthDst(dst.mac()).build(); + return PathIntent.builder() + .appId(intent.appId()) + .selector(selector) + .treatment(intent.treatment()) + .path(path) + .constraints(intent.constraints()) + .priority(intent.priority()) + .build(); + } + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java new file mode 100644 index 00000000..76c5736d --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java @@ -0,0 +1,138 @@ +/* + * 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.intent.impl.compiler; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.SetMultimap; +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.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.DefaultFlowRule; +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.IntentCompiler; +import org.onosproject.net.intent.IntentExtensionService; +import org.onosproject.net.intent.LinkCollectionIntent; +import org.onosproject.net.resource.link.LinkResourceAllocations; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Component(immediate = true) +public class LinkCollectionIntentCompiler implements IntentCompiler { + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentExtensionService intentManager; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + private ApplicationId appId; + + @Activate + public void activate() { + appId = coreService.registerApplication("org.onosproject.net.intent"); + intentManager.registerCompiler(LinkCollectionIntent.class, this); + } + + @Deactivate + public void deactivate() { + intentManager.unregisterCompiler(LinkCollectionIntent.class); + } + + @Override + public List compile(LinkCollectionIntent intent, List installable, + Set resources) { + SetMultimap inputPorts = HashMultimap.create(); + SetMultimap outputPorts = HashMultimap.create(); + + for (Link link : intent.links()) { + inputPorts.put(link.dst().deviceId(), link.dst().port()); + outputPorts.put(link.src().deviceId(), link.src().port()); + } + + for (ConnectPoint ingressPoint : intent.ingressPoints()) { + inputPorts.put(ingressPoint.deviceId(), ingressPoint.port()); + } + + for (ConnectPoint egressPoint : intent.egressPoints()) { + outputPorts.put(egressPoint.deviceId(), egressPoint.port()); + } + + List rules = new ArrayList<>(); + for (DeviceId deviceId: outputPorts.keys()) { + rules.addAll(createRules(intent, deviceId, inputPorts.get(deviceId), outputPorts.get(deviceId))); + } + return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources())); + } + + private List createRules(LinkCollectionIntent intent, DeviceId deviceId, + Set inPorts, Set outPorts) { + Set ingressPorts = intent.ingressPoints().stream() + .filter(point -> point.deviceId().equals(deviceId)) + .map(ConnectPoint::port) + .collect(Collectors.toSet()); + + TrafficTreatment.Builder defaultTreatmentBuilder = DefaultTrafficTreatment.builder(); + outPorts.stream() + .forEach(defaultTreatmentBuilder::setOutput); + TrafficTreatment defaultTreatment = defaultTreatmentBuilder.build(); + + TrafficTreatment.Builder ingressTreatmentBuilder = DefaultTrafficTreatment.builder(intent.treatment()); + outPorts.stream() + .forEach(ingressTreatmentBuilder::setOutput); + TrafficTreatment ingressTreatment = ingressTreatmentBuilder.build(); + + List rules = new ArrayList<>(inPorts.size()); + for (PortNumber inPort: inPorts) { + TrafficSelector selector = DefaultTrafficSelector.builder(intent.selector()).matchInPort(inPort).build(); + TrafficTreatment treatment; + if (ingressPorts.contains(inPort)) { + treatment = ingressTreatment; + } else { + treatment = defaultTreatment; + } + + FlowRule rule = DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector) + .withTreatment(treatment) + .withPriority(intent.priority()) + .fromApp(appId) + .makePermanent() + .build(); + rules.add(rule); + } + + return rules; + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsIntentCompiler.java new file mode 100644 index 00000000..609f9a34 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsIntentCompiler.java @@ -0,0 +1,91 @@ +package org.onosproject.net.intent.impl.compiler; + +import static java.util.Arrays.asList; +import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultPath; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.MplsIntent; +import org.onosproject.net.intent.MplsPathIntent; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.net.resource.link.LinkResourceAllocations; + + +@Component(immediate = true) +public class MplsIntentCompiler extends ConnectivityIntentCompiler { + + // TODO: use off-the-shell core provider ID + private static final ProviderId PID = + new ProviderId("core", "org.onosproject.core", true); + // TODO: consider whether the default cost is appropriate or not + public static final int DEFAULT_COST = 1; + + + @Activate + public void activate() { + intentManager.registerCompiler(MplsIntent.class, this); + } + + @Deactivate + public void deactivate() { + intentManager.unregisterCompiler(MplsIntent.class); + } + + @Override + public List compile(MplsIntent intent, List installable, + Set resources) { + ConnectPoint ingressPoint = intent.ingressPoint(); + ConnectPoint egressPoint = intent.egressPoint(); + + if (ingressPoint.deviceId().equals(egressPoint.deviceId())) { + List links = asList(createEdgeLink(ingressPoint, true), createEdgeLink(egressPoint, false)); + return asList(createPathIntent(new DefaultPath(PID, links, DEFAULT_COST), intent)); + } + + List links = new ArrayList<>(); + Path path = getPath(intent, ingressPoint.deviceId(), + egressPoint.deviceId()); + + links.add(createEdgeLink(ingressPoint, true)); + links.addAll(path.links()); + + links.add(createEdgeLink(egressPoint, false)); + + return asList(createPathIntent(new DefaultPath(PID, links, path.cost(), + path.annotations()), intent)); + } + + /** + * Creates a path intent from the specified path and original + * connectivity intent. + * + * @param path path to create an intent for + * @param intent original intent + */ + private Intent createPathIntent(Path path, + MplsIntent intent) { + return MplsPathIntent.builder() + .appId(intent.appId()) + .selector(intent.selector()) + .treatment(intent.treatment()) + .path(path) + .ingressLabel(intent.ingressLabel()) + .egressLabel(intent.egressLabel()) + .constraints(intent.constraints()) + .priority(intent.priority()) + .build(); + } + + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java new file mode 100644 index 00000000..5fd1c85d --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MplsPathIntentCompiler.java @@ -0,0 +1,291 @@ +/* + * 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.intent.impl.compiler; + +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; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onlab.packet.EthType; +import org.onlab.packet.Ethernet; +import org.onlab.packet.VlanId; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.PortNumber; +import org.onosproject.net.flow.DefaultFlowRule; +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.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.EthTypeCriterion; +import org.onosproject.net.flow.instructions.Instruction; +import org.onosproject.net.flow.instructions.L2ModificationInstruction; +import org.onosproject.net.intent.FlowRuleIntent; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentCompiler; +import org.onosproject.net.intent.IntentExtensionService; +import org.onosproject.net.intent.MplsPathIntent; +import org.onosproject.net.link.LinkStore; +import org.onosproject.net.resource.link.DefaultLinkResourceRequest; +import org.onosproject.net.resource.link.LinkResourceAllocations; +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.ResourceType; +import org.slf4j.Logger; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.slf4j.LoggerFactory.getLogger; + +@Component(immediate = true) +public class MplsPathIntentCompiler implements IntentCompiler { + + private final Logger log = getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentExtensionService intentExtensionService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LinkResourceService resourceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LinkStore linkStore; + + protected ApplicationId appId; + + @Override + public List compile(MplsPathIntent intent, List installable, + Set resources) { + LinkResourceAllocations allocations = assignMplsLabel(intent); + List rules = generateRules(intent, allocations); + + return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources())); + } + + @Activate + public void activate() { + appId = coreService.registerApplication("org.onosproject.net.intent"); + intentExtensionService.registerCompiler(MplsPathIntent.class, this); + } + + @Deactivate + public void deactivate() { + intentExtensionService.unregisterCompiler(MplsPathIntent.class); + } + + private LinkResourceAllocations assignMplsLabel(MplsPathIntent intent) { + // TODO: do it better... Suggestions? + Set linkRequest = Sets.newHashSetWithExpectedSize(intent.path() + .links().size() - 2); + for (int i = 1; i <= intent.path().links().size() - 2; i++) { + Link link = intent.path().links().get(i); + linkRequest.add(link); + // add the inverse link. I want that the label is reserved both for + // the direct and inverse link + linkRequest.add(linkStore.getLink(link.dst(), link.src())); + } + + LinkResourceRequest.Builder request = DefaultLinkResourceRequest + .builder(intent.id(), linkRequest).addMplsRequest(); + LinkResourceAllocations reqMpls = resourceService + .requestResources(request.build()); + return reqMpls; + } + + private MplsLabel getMplsLabel(LinkResourceAllocations allocations, Link link) { + for (ResourceAllocation allocation : allocations + .getResourceAllocation(link)) { + if (allocation.type() == ResourceType.MPLS_LABEL) { + return ((MplsLabelResourceAllocation) allocation).mplsLabel(); + + } + } + log.warn("MPLS label was not assigned successfully"); + return null; + } + + private List generateRules(MplsPathIntent intent, + LinkResourceAllocations allocations) { + + Iterator links = intent.path().links().iterator(); + Link srcLink = links.next(); + ConnectPoint prev = srcLink.dst(); + + Link link = links.next(); + // List of flow rules to be installed + List rules = new LinkedList<>(); + + // Ingress traffic + // Get the new MPLS label + MplsLabel mpls = getMplsLabel(allocations, link); + checkNotNull(mpls); + MplsLabel prevLabel = mpls; + rules.add(ingressFlow(prev.port(), link, intent, mpls)); + + prev = link.dst(); + + while (links.hasNext()) { + + link = links.next(); + + if (links.hasNext()) { + // Transit traffic + // Get the new MPLS label + mpls = getMplsLabel(allocations, link); + checkNotNull(mpls); + rules.add(transitFlow(prev.port(), link, intent, + prevLabel, mpls)); + prevLabel = mpls; + + } else { + // Egress traffic + rules.add(egressFlow(prev.port(), link, intent, + prevLabel)); + } + + prev = link.dst(); + } + return rules; + } + + private FlowRule ingressFlow(PortNumber inPort, Link link, + MplsPathIntent intent, MplsLabel label) { + + TrafficSelector.Builder ingressSelector = DefaultTrafficSelector + .builder(intent.selector()); + TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(); + ingressSelector.matchInPort(inPort); + + if (intent.ingressLabel().isPresent()) { + ingressSelector.matchEthType(Ethernet.MPLS_UNICAST) + .matchMplsLabel(intent.ingressLabel().get()); + + // Swap the MPLS label + treat.setMpls(label.label()); + } else { + // Push and set the MPLS label + treat.pushMpls().setMpls(label.label()); + } + // Add the output action + treat.setOutput(link.src().port()); + + return createFlowRule(intent, link.src().deviceId(), ingressSelector.build(), treat.build()); + } + + private FlowRule transitFlow(PortNumber inPort, Link link, + MplsPathIntent intent, + MplsLabel prevLabel, + MplsLabel outLabel) { + + // Ignore the ingress Traffic Selector and use only the MPLS label + // assigned in the previous link + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST) + .matchMplsLabel(prevLabel.label()); + TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(); + + // Set the new label only if the label on the packet is + // different + if (!prevLabel.equals(outLabel)) { + treat.setMpls(outLabel.label()); + } + + treat.setOutput(link.src().port()); + return createFlowRule(intent, link.src().deviceId(), selector.build(), treat.build()); + } + + private FlowRule egressFlow(PortNumber inPort, Link link, + MplsPathIntent intent, + MplsLabel prevLabel) { + // egress point: either set the egress MPLS label or pop the + // MPLS label based on the intent annotations + + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); + selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST) + .matchMplsLabel(prevLabel.label()); + + // apply the intent's treatments + TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(intent + .treatment()); + + // check if the treatement is popVlan or setVlan (rewrite), + // than selector needs to match any VlanId + for (Instruction instruct : intent.treatment().allInstructions()) { + if (instruct instanceof L2ModificationInstruction) { + L2ModificationInstruction l2Mod = (L2ModificationInstruction) instruct; + if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) { + break; + } + if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP || + l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) { + selector.matchVlanId(VlanId.ANY); + } + } + } + + if (intent.egressLabel().isPresent()) { + treat.setMpls(intent.egressLabel().get()); + } else { + treat.popMpls(outputEthType(intent.selector())); + } + treat.setOutput(link.src().port()); + return createFlowRule(intent, link.src().deviceId(), + selector.build(), treat.build()); + } + + protected FlowRule createFlowRule(MplsPathIntent intent, DeviceId deviceId, + TrafficSelector selector, TrafficTreatment treat) { + return DefaultFlowRule.builder() + .forDevice(deviceId) + .withSelector(selector) + .withTreatment(treat) + .withPriority(intent.priority()) + .fromApp(appId) + .makePermanent() + .build(); + } + + // if the ingress ethertype is defined, the egress traffic + // will be use that value, otherwise the IPv4 ethertype is used. + private EthType outputEthType(TrafficSelector selector) { + Criterion c = selector.getCriterion(Criterion.Type.ETH_TYPE); + if (c != null && c instanceof EthTypeCriterion) { + EthTypeCriterion ethertype = (EthTypeCriterion) c; + return ethertype.ethType(); + } else { + return EthType.EtherType.IPV4.ethType(); + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java new file mode 100644 index 00000000..06d0e9a2 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java @@ -0,0 +1,151 @@ +/* + * Copyright 2014-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.intent.impl.compiler; + +import com.google.common.collect.ImmutableSet; +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; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentCompiler; +import org.onosproject.net.intent.IntentException; +import org.onosproject.net.intent.IntentExtensionService; +import org.onosproject.net.intent.LinkCollectionIntent; +import org.onosproject.net.intent.MultiPointToSinglePointIntent; +import org.onosproject.net.intent.PointToPointIntent; +import org.onosproject.net.resource.link.LinkResourceAllocations; +import org.onosproject.net.topology.PathService; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure; + + +/** + * An intent compiler for + * {@link org.onosproject.net.intent.MultiPointToSinglePointIntent}. + */ +@Component(immediate = true) +public class MultiPointToSinglePointIntentCompiler + implements IntentCompiler { + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentExtensionService intentManager; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected PathService pathService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Activate + public void activate() { + intentManager.registerCompiler(MultiPointToSinglePointIntent.class, this); + } + + @Deactivate + public void deactivate() { + intentManager.unregisterCompiler(PointToPointIntent.class); + } + + @Override + public List compile(MultiPointToSinglePointIntent intent, List installable, + Set resources) { + Map links = new HashMap<>(); + ConnectPoint egressPoint = intent.egressPoint(); + + final boolean allowMissingPaths = intentAllowsPartialFailure(intent); + boolean partialTree = false; + boolean anyMissingPaths = false; + for (ConnectPoint ingressPoint : intent.ingressPoints()) { + if (ingressPoint.deviceId().equals(egressPoint.deviceId())) { + if (deviceService.isAvailable(ingressPoint.deviceId())) { + partialTree = true; + } else { + anyMissingPaths = true; + } + + continue; + } + + Path path = getPath(ingressPoint, intent.egressPoint()); + if (path != null) { + partialTree = true; + + for (Link link : path.links()) { + if (links.containsKey(link.dst().deviceId())) { + // We've already reached the existing tree with the first + // part of this path. Add the merging point with different + // incoming port, but don't add the remainder of the path + // in case it differs from the path we already have. + links.put(link.src().deviceId(), link); + break; + } + links.put(link.src().deviceId(), link); + } + } else { + anyMissingPaths = true; + } + } + + if (!partialTree) { + throw new IntentException("Could not find any paths between ingress and egress points."); + } else if (!allowMissingPaths && anyMissingPaths) { + throw new IntentException("Missing some paths between ingress and egress ports."); + } + + Intent result = LinkCollectionIntent.builder() + .appId(intent.appId()) + .selector(intent.selector()) + .treatment(intent.treatment()) + .links(Sets.newHashSet(links.values())) + .ingressPoints(intent.ingressPoints()) + .egressPoints(ImmutableSet.of(intent.egressPoint())) + .priority(intent.priority()) + .constraints(intent.constraints()) + .build(); + + return Collections.singletonList(result); + } + + /** + * Computes a path between two ConnectPoints. + * + * @param one start of the path + * @param two end of the path + * @return Path between the two + */ + private Path getPath(ConnectPoint one, ConnectPoint two) { + Set paths = pathService.getPaths(one.deviceId(), two.deviceId()); + if (paths.isEmpty()) { + return null; + } + // TODO: let's be more intelligent about this eventually + return paths.iterator().next(); + } +} 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 new file mode 100644 index 00000000..99f58df7 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalCircuitIntentCompiler.java @@ -0,0 +1,372 @@ +/* + * 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.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; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onlab.util.Tools; +import org.onosproject.cfg.ComponentConfigService; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.AnnotationKeys; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.OchPort; +import org.onosproject.net.OduCltPort; +import org.onosproject.net.OduSignalType; +import org.onosproject.net.Port; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.flow.DefaultFlowRule; +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.IntentCompiler; +import org.onosproject.net.intent.IntentExtensionService; +import org.onosproject.net.intent.IntentId; +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.resource.link.LinkResourceAllocations; +import org.osgi.service.component.ComponentContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.Dictionary; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * An intent compiler for {@link org.onosproject.net.intent.OpticalCircuitIntent}. + */ +@Component(immediate = true) +public class OpticalCircuitIntentCompiler implements IntentCompiler { + + private static final Logger log = LoggerFactory.getLogger(OpticalCircuitIntentCompiler.class); + + private static final int DEFAULT_MAX_CAPACITY = 10; + + @Property(name = "maxCapacity", intValue = DEFAULT_MAX_CAPACITY, + label = "Maximum utilization of an optical connection.") + + private int maxCapacity = DEFAULT_MAX_CAPACITY; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ComponentConfigService cfgService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentExtensionService intentManager; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceResourceService deviceResourceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentService intentService; + + private ApplicationId appId; + + @Modified + public void modified(ComponentContext context) { + Dictionary properties = context.getProperties(); + + //TODO for reduction check if the new capacity is smaller than the size of the current mapping + String propertyString = Tools.get(properties, "maxCapacity"); + + //Ignore if propertyString is empty + if (!propertyString.isEmpty()) { + try { + int temp = Integer.parseInt(propertyString); + //Ensure value is non-negative but allow zero as a way to shutdown the link + if (temp >= 0) { + maxCapacity = temp; + } + } catch (NumberFormatException e) { + //Malformed arguments lead to no change of value (user should be notified of error) + log.error("The value '{}' for maxCapacity was not parsable as an integer.", propertyString, e); + } + } else { + //Notify of empty value but do not return (other properties will also go in this function) + log.error("The value for maxCapacity was set to an empty value."); + } + + } + + @Activate + public void activate(ComponentContext context) { + appId = coreService.registerApplication("org.onosproject.net.intent"); + intentManager.registerCompiler(OpticalCircuitIntent.class, this); + cfgService.registerProperties(getClass()); + modified(context); + } + + @Deactivate + public void deactivate() { + intentManager.unregisterCompiler(OpticalCircuitIntent.class); + cfgService.unregisterProperties(getClass(), false); + } + + @Override + public List compile(OpticalCircuitIntent intent, List installable, + Set resources) { + // Check if ports are OduClt ports + ConnectPoint src = intent.getSrc(); + ConnectPoint dst = intent.getDst(); + Port srcPort = deviceService.getPort(src.deviceId(), src.port()); + Port dstPort = deviceService.getPort(dst.deviceId(), dst.port()); + checkArgument(srcPort instanceof OduCltPort); + checkArgument(dstPort instanceof OduCltPort); + + log.debug("Compiling optical circuit intent between {} and {}", src, dst); + + // Reserve OduClt ports + if (!deviceResourceService.requestPorts(Sets.newHashSet(srcPort, dstPort), intent)) { + throw new IntentCompilationException("Unable to reserve ports for intent " + intent); + } + + LinkedList intents = new LinkedList<>(); + + FlowRuleIntent circuitIntent; + OpticalConnectivityIntent connIntent = findOpticalConnectivityIntent(intent); + + // Create optical connectivity intent if needed + if (connIntent == null) { + // Find OCh ports with available resources + Pair ochPorts = findPorts(intent); + + if (ochPorts == null) { + return Collections.emptyList(); + } + + // Create optical connectivity intent + ConnectPoint srcCP = new ConnectPoint(src.elementId(), ochPorts.getLeft().number()); + ConnectPoint dstCP = new ConnectPoint(dst.elementId(), ochPorts.getRight().number()); + // FIXME: hardcoded ODU signal type + connIntent = OpticalConnectivityIntent.builder() + .appId(appId) + .src(srcCP) + .dst(dstCP) + .signalType(OduSignalType.ODU4) + .bidirectional(intent.isBidirectional()) + .build(); + intentService.submit(connIntent); + } + + // Create optical circuit intent + List rules = new LinkedList<>(); + rules.add(connectPorts(src, connIntent.getSrc(), intent.priority())); + rules.add(connectPorts(connIntent.getDst(), dst, intent.priority())); + + // Create flow rules for reverse path + if (intent.isBidirectional()) { + rules.add(connectPorts(connIntent.getSrc(), src, intent.priority())); + rules.add(connectPorts(dst, connIntent.getDst(), intent.priority())); + } + + circuitIntent = new FlowRuleIntent(appId, rules, intent.resources()); + + // Save circuit to connectivity intent mapping + deviceResourceService.requestMapping(connIntent.id(), intent.id()); + intents.add(circuitIntent); + + return intents; + } + + /** + * Checks if current allocations on given resource can satisfy request. + * If the resource is null, return true. + * + * @param request the intent making the request + * @param resource the resource on which to map the intent + * @return true if the resource can accept the request, false otherwise + */ + private boolean isAvailable(Intent request, IntentId resource) { + if (resource == null) { + return true; + } + + Set mapping = deviceResourceService.getMapping(resource); + + if (mapping == null) { + return true; + } + + return mapping.size() < maxCapacity; + } + + private boolean isAllowed(OpticalCircuitIntent circuitIntent, OpticalConnectivityIntent connIntent) { + ConnectPoint srcStaticPort = staticPort(circuitIntent.getSrc()); + if (srcStaticPort != null) { + if (!srcStaticPort.equals(connIntent.getSrc())) { + return false; + } + } + + ConnectPoint dstStaticPort = staticPort(circuitIntent.getDst()); + if (dstStaticPort != null) { + if (!dstStaticPort.equals(connIntent.getDst())) { + return false; + } + } + + return true; + } + + /** + * Returns existing and available optical connectivity intent that matches the given circuit intent. + * + * @param circuitIntent optical circuit intent + * @return existing optical connectivity intent, null otherwise. + */ + private OpticalConnectivityIntent findOpticalConnectivityIntent(OpticalCircuitIntent circuitIntent) { + for (Intent intent : intentService.getIntents()) { + if (!(intent instanceof OpticalConnectivityIntent)) { + continue; + } + + OpticalConnectivityIntent connIntent = (OpticalConnectivityIntent) intent; + + ConnectPoint src = circuitIntent.getSrc(); + ConnectPoint dst = circuitIntent.getDst(); + // Ignore if the intents don't have identical src and dst devices + if (!src.deviceId().equals(connIntent.getSrc().deviceId()) && + !dst.deviceId().equals(connIntent.getDst().deviceId())) { + continue; + } + + if (!isAllowed(circuitIntent, connIntent)) { + continue; + } + + if (isAvailable(circuitIntent, connIntent.id())) { + return connIntent; + } + } + + return null; + } + + private ConnectPoint staticPort(ConnectPoint connectPoint) { + Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port()); + + String staticPort = port.annotations().value(AnnotationKeys.STATIC_PORT); + + // FIXME: need a better way to match the port + if (staticPort != null) { + for (Port p : deviceService.getPorts(connectPoint.deviceId())) { + if (staticPort.equals(p.number().name())) { + return new ConnectPoint(p.element().id(), p.number()); + } + } + } + + return null; + } + + private OchPort findAvailableOchPort(ConnectPoint oduPort, OpticalCircuitIntent circuitIntent) { + // First see if the port mappings are constrained + ConnectPoint ochCP = staticPort(oduPort); + + if (ochCP != null) { + OchPort ochPort = (OchPort) deviceService.getPort(ochCP.deviceId(), ochCP.port()); + IntentId intentId = deviceResourceService.getAllocations(ochPort); + if (isAvailable(circuitIntent, intentId)) { + return ochPort; + } + } + + // No port constraints, so find any port that works + List ports = deviceService.getPorts(oduPort.deviceId()); + + for (Port port : ports) { + if (!(port instanceof OchPort)) { + continue; + } + + IntentId intentId = deviceResourceService.getAllocations(port); + if (isAvailable(circuitIntent, intentId)) { + return (OchPort) port; + } + } + + return null; + } + + private Pair findPorts(OpticalCircuitIntent intent) { + + OchPort srcPort = findAvailableOchPort(intent.getSrc(), intent); + if (srcPort == null) { + return null; + } + + OchPort dstPort = findAvailableOchPort(intent.getDst(), intent); + if (dstPort == null) { + return null; + } + + return Pair.of(srcPort, dstPort); + } + + /** + * Builds flow rule for mapping between two ports. + * + * @param src source port + * @param dst destination port + * @return flow rules + */ + private FlowRule connectPorts(ConnectPoint src, ConnectPoint dst, int priority) { + checkArgument(src.deviceId().equals(dst.deviceId())); + + TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); + TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder(); + + selectorBuilder.matchInPort(src.port()); + //selectorBuilder.add(Criteria.matchCltSignalType) + treatmentBuilder.setOutput(dst.port()); + //treatmentBuilder.add(Instructions.modL1OduSignalType) + + FlowRule flowRule = DefaultFlowRule.builder() + .forDevice(src.deviceId()) + .withSelector(selectorBuilder.build()) + .withTreatment(treatmentBuilder.build()) + .withPriority(priority) + .fromApp(appId) + .makePermanent() + .build(); + + return flowRule; + } +} 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 new file mode 100644 index 00000000..c60325a7 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java @@ -0,0 +1,305 @@ +/* + * Copyright 2014-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.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; +import org.onlab.util.Frequency; +import org.onosproject.net.AnnotationKeys; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.OchPort; +import org.onosproject.net.OchSignal; +import org.onosproject.net.OchSignalType; +import org.onosproject.net.OmsPort; +import org.onosproject.net.Path; +import org.onosproject.net.Port; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentCompiler; +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.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; +import org.onosproject.net.resource.link.LinkResourceAllocations; +import org.onosproject.net.resource.link.LinkResourceRequest; +import org.onosproject.net.resource.link.LinkResourceService; +import org.onosproject.net.topology.LinkWeight; +import org.onosproject.net.topology.Topology; +import org.onosproject.net.topology.TopologyEdge; +import org.onosproject.net.topology.TopologyService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkArgument; + +/** + * An intent compiler for {@link org.onosproject.net.intent.OpticalConnectivityIntent}. + */ +@Component(immediate = true) +public class OpticalConnectivityIntentCompiler implements IntentCompiler { + + protected static final Logger log = LoggerFactory.getLogger(OpticalConnectivityIntentCompiler.class); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentExtensionService intentManager; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected TopologyService topologyService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LinkResourceService linkResourceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceResourceService deviceResourceService; + + @Activate + public void activate() { + intentManager.registerCompiler(OpticalConnectivityIntent.class, this); + } + + @Deactivate + public void deactivate() { + intentManager.unregisterCompiler(OpticalConnectivityIntent.class); + } + + @Override + public List compile(OpticalConnectivityIntent intent, + List installable, + Set resources) { + // Check if source and destination are optical OCh ports + ConnectPoint src = intent.getSrc(); + ConnectPoint dst = intent.getDst(); + Port srcPort = deviceService.getPort(src.deviceId(), src.port()); + Port dstPort = deviceService.getPort(dst.deviceId(), dst.port()); + checkArgument(srcPort instanceof OchPort); + checkArgument(dstPort instanceof OchPort); + + log.debug("Compiling optical connectivity intent between {} and {}", src, dst); + + // Reserve OCh ports + if (!deviceResourceService.requestPorts(ImmutableSet.of(srcPort, dstPort), intent)) { + throw new IntentCompilationException("Unable to reserve ports for intent " + intent); + } + + // Calculate available light paths + Set paths = getOpticalPaths(intent); + + // Use first path that can be successfully reserved + for (Path path : paths) { + + // Static or dynamic lambda allocation + String staticLambda = srcPort.annotations().value(AnnotationKeys.STATIC_LAMBDA); + OchPort srcOchPort = (OchPort) srcPort; + OchPort dstOchPort = (OchPort) dstPort; + OchSignal ochSignal; + + // FIXME: need to actually reserve the lambda for static lambda's + if (staticLambda != null) { + ochSignal = new OchSignal(Frequency.ofHz(Long.parseLong(staticLambda)), + srcOchPort.lambda().channelSpacing(), + srcOchPort.lambda().slotGranularity()); + } else if (!srcOchPort.isTunable() || !dstOchPort.isTunable()) { + // FIXME: also check OCh port + ochSignal = srcOchPort.lambda(); + } else { + // Request and reserve lambda on path + LinkResourceAllocations linkAllocs = assignWavelength(intent, path); + if (linkAllocs == null) { + continue; + } + LambdaResourceAllocation lambdaAlloc = getWavelength(path, linkAllocs); + OmsPort omsPort = (OmsPort) deviceService.getPort(path.src().deviceId(), path.src().port()); + ochSignal = new OchSignal(lambdaAlloc.lambda().toInt(), omsPort.maxFrequency(), omsPort.grid()); + } + + // Create installable optical path intent + // Only support fixed grid for now + OchSignalType signalType = OchSignalType.FIXED_GRID; + + Intent newIntent = OpticalPathIntent.builder() + .appId(intent.appId()) + .src(intent.getSrc()) + .dst(intent.getDst()) + .path(path) + .lambda(ochSignal) + .signalType(signalType) + .bidirectional(intent.isBidirectional()) + .build(); + + return ImmutableList.of(newIntent); + } + + // Release port allocations if unsuccessful + deviceResourceService.releasePorts(intent.id()); + + throw new IntentCompilationException("Unable to find suitable lightpath for intent " + intent); + } + + /** + * Find the lambda allocated to the path. + * + * @param path the path + * @param linkAllocs the link allocations + * @return lambda allocated to the given path + */ + private LambdaResourceAllocation getWavelength(Path path, LinkResourceAllocations linkAllocs) { + for (Link link : path.links()) { + for (ResourceAllocation alloc : linkAllocs.getResourceAllocation(link)) { + if (alloc.type() == ResourceType.LAMBDA) { + return (LambdaResourceAllocation) alloc; + } + } + } + + return null; + } + + /** + * Request and reserve first available wavelength across path. + * + * @param path path in WDM topology + * @return first available lambda resource allocation + */ + private LinkResourceAllocations assignWavelength(Intent intent, Path path) { + LinkResourceRequest.Builder request = + DefaultLinkResourceRequest.builder(intent.id(), path.links()) + .addLambdaRequest(); + + LinkResourceAllocations allocations = linkResourceService.requestResources(request.build()); + + if (!checkWavelengthContinuity(allocations, path)) { + linkResourceService.releaseResources(allocations); + return null; + } + + return allocations; + } + + /** + * Checks wavelength continuity constraint across path, i.e., an identical lambda is used on all links. + * @return true if wavelength continuity is met, false otherwise + */ + private boolean checkWavelengthContinuity(LinkResourceAllocations allocations, Path path) { + if (allocations == null) { + return false; + } + + LambdaResource lambda = null; + + 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; + } + } + } + } + + return true; + } + + private ConnectPoint staticPort(ConnectPoint connectPoint) { + Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port()); + + String staticPort = port.annotations().value(AnnotationKeys.STATIC_PORT); + + // FIXME: need a better way to match the port + if (staticPort != null) { + for (Port p : deviceService.getPorts(connectPoint.deviceId())) { + if (staticPort.equals(p.number().name())) { + return new ConnectPoint(p.element().id(), p.number()); + } + } + } + + return null; + } + + /** + * Calculates optical paths in WDM topology. + * + * @param intent optical connectivity intent + * @return set of paths in WDM topology + */ + private Set getOpticalPaths(OpticalConnectivityIntent intent) { + // Route in WDM topology + Topology topology = topologyService.currentTopology(); + LinkWeight weight = new LinkWeight() { + @Override + public double weight(TopologyEdge edge) { + // Disregard inactive or non-optical links + if (edge.link().state() == Link.State.INACTIVE) { + return -1; + } + if (edge.link().type() != Link.Type.OPTICAL) { + return -1; + } + // Adhere to static port mappings + DeviceId srcDeviceId = edge.link().src().deviceId(); + if (srcDeviceId.equals(intent.getSrc().deviceId())) { + ConnectPoint srcStaticPort = staticPort(intent.getSrc()); + if (srcStaticPort != null) { + return srcStaticPort.equals(edge.link().src()) ? 1 : -1; + } + } + DeviceId dstDeviceId = edge.link().dst().deviceId(); + if (dstDeviceId.equals(intent.getDst().deviceId())) { + ConnectPoint dstStaticPort = staticPort(intent.getDst()); + if (dstStaticPort != null) { + return dstStaticPort.equals(edge.link().dst()) ? 1 : -1; + } + } + + return 1; + } + }; + + ConnectPoint start = intent.getSrc(); + ConnectPoint end = intent.getDst(); + Set paths = topologyService.getPaths(topology, start.deviceId(), + end.deviceId(), weight); + + return paths; + } +} 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 new file mode 100644 index 00000000..ca9ae5cc --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java @@ -0,0 +1,195 @@ +/* + * 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.intent.impl.compiler; + +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; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Link; +import org.onosproject.net.flow.DefaultFlowRule; +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.flow.criteria.Criteria; +import org.onosproject.net.flow.instructions.Instructions; +import org.onosproject.net.intent.FlowRuleIntent; +import org.onosproject.net.intent.Intent; +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; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +@Component(immediate = true) +public class OpticalPathIntentCompiler implements IntentCompiler { + + private static final Logger log = LoggerFactory.getLogger(OpticalPathIntentCompiler.class); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentExtensionService intentManager; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LinkResourceService resourceService; + + private ApplicationId appId; + + @Activate + public void activate() { + appId = coreService.registerApplication("org.onosproject.net.intent"); + intentManager.registerCompiler(OpticalPathIntent.class, this); + } + + @Deactivate + public void deactivate() { + intentManager.unregisterCompiler(OpticalPathIntent.class); + } + + @Override + public List compile(OpticalPathIntent intent, List installable, + Set resources) { + log.debug("Compiling optical path intent between {} and {}", intent.src(), intent.dst()); + + // Create rules for forward and reverse path + List rules = createRules(intent); + if (intent.isBidirectional()) { + rules.addAll(createReverseRules(intent)); + } + + return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources())); + } + + /** + * Create rules for the forward path of the intent. + * + * @param intent the intent + * @return list of flow rules + */ + private List createRules(OpticalPathIntent intent) { + TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); + selectorBuilder.matchInPort(intent.src().port()); + + List rules = new LinkedList<>(); + ConnectPoint current = intent.src(); + + for (Link link : intent.path().links()) { + TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder(); + treatmentBuilder.add(Instructions.modL0Lambda(intent.lambda())); + treatmentBuilder.setOutput(link.src().port()); + + FlowRule rule = DefaultFlowRule.builder() + .forDevice(current.deviceId()) + .withSelector(selectorBuilder.build()) + .withTreatment(treatmentBuilder.build()) + .withPriority(intent.priority()) + .fromApp(appId) + .makePermanent() + .build(); + + rules.add(rule); + + current = link.dst(); + selectorBuilder.matchInPort(link.dst().port()); + selectorBuilder.add(Criteria.matchLambda(intent.lambda())); + selectorBuilder.add(Criteria.matchOchSignalType(intent.signalType())); + } + + // Build the egress ROADM rule + TrafficTreatment.Builder treatmentLast = DefaultTrafficTreatment.builder(); + treatmentLast.setOutput(intent.dst().port()); + + FlowRule rule = new DefaultFlowRule.Builder() + .forDevice(intent.dst().deviceId()) + .withSelector(selectorBuilder.build()) + .withTreatment(treatmentLast.build()) + .withPriority(intent.priority()) + .fromApp(appId) + .makePermanent() + .build(); + rules.add(rule); + + return rules; + } + + /** + * Create rules for the reverse path of the intent. + * + * @param intent the intent + * @return list of flow rules + */ + private List createReverseRules(OpticalPathIntent intent) { + TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); + selectorBuilder.matchInPort(intent.dst().port()); + + List rules = new LinkedList<>(); + ConnectPoint current = intent.dst(); + + for (Link link : Lists.reverse(intent.path().links())) { + TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder(); + treatmentBuilder.add(Instructions.modL0Lambda(intent.lambda())); + treatmentBuilder.setOutput(link.dst().port()); + + FlowRule rule = DefaultFlowRule.builder() + .forDevice(current.deviceId()) + .withSelector(selectorBuilder.build()) + .withTreatment(treatmentBuilder.build()) + .withPriority(intent.priority()) + .fromApp(appId) + .makePermanent() + .build(); + + rules.add(rule); + + current = link.src(); + selectorBuilder.matchInPort(link.src().port()); + selectorBuilder.add(Criteria.matchLambda(intent.lambda())); + selectorBuilder.add(Criteria.matchOchSignalType(intent.signalType())); + } + + // Build the egress ROADM rule + TrafficTreatment.Builder treatmentLast = DefaultTrafficTreatment.builder(); + treatmentLast.setOutput(intent.src().port()); + + FlowRule rule = new DefaultFlowRule.Builder() + .forDevice(intent.src().deviceId()) + .withSelector(selectorBuilder.build()) + .withTreatment(treatmentLast.build()) + .withPriority(intent.priority()) + .fromApp(appId) + .makePermanent() + .build(); + rules.add(rule); + + return rules; + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java new file mode 100644 index 00000000..7add2173 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java @@ -0,0 +1,116 @@ +/* + * 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.intent.impl.compiler; + +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.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Link; +import org.onosproject.net.flow.DefaultFlowRule; +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.IntentCompiler; +import org.onosproject.net.intent.IntentExtensionService; +import org.onosproject.net.intent.PathIntent; +import org.onosproject.net.resource.link.LinkResourceAllocations; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +@Component(immediate = true) +public class PathIntentCompiler implements IntentCompiler { + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentExtensionService intentManager; + + private ApplicationId appId; + + @Activate + public void activate() { + appId = coreService.registerApplication("org.onosproject.net.intent"); + intentManager.registerCompiler(PathIntent.class, this); + } + + @Deactivate + public void deactivate() { + intentManager.unregisterCompiler(PathIntent.class); + } + + @Override + public List compile(PathIntent intent, List installable, + Set resources) { + // Note: right now recompile is not considered + // TODO: implement recompile behavior + + List links = intent.path().links(); + List rules = new ArrayList<>(links.size() - 1); + + for (int i = 0; i < links.size() - 1; i++) { + ConnectPoint ingress = links.get(i).dst(); + ConnectPoint egress = links.get(i + 1).src(); + FlowRule rule = createFlowRule(intent.selector(), intent.treatment(), + ingress, egress, intent.priority(), + isLast(links, i)); + rules.add(rule); + } + + return Collections.singletonList(new FlowRuleIntent(appId, null, rules, intent.resources())); + } + + private FlowRule createFlowRule(TrafficSelector originalSelector, TrafficTreatment originalTreatment, + ConnectPoint ingress, ConnectPoint egress, + int priority, boolean last) { + TrafficSelector selector = DefaultTrafficSelector.builder(originalSelector) + .matchInPort(ingress.port()) + .build(); + + TrafficTreatment.Builder treatmentBuilder; + if (last) { + treatmentBuilder = DefaultTrafficTreatment.builder(originalTreatment); + } else { + treatmentBuilder = DefaultTrafficTreatment.builder(); + } + TrafficTreatment treatment = treatmentBuilder.setOutput(egress.port()).build(); + + return DefaultFlowRule.builder() + .forDevice(ingress.deviceId()) + .withSelector(selector) + .withTreatment(treatment) + .withPriority(priority) + .fromApp(appId) + .makePermanent() + .build(); + } + + private boolean isLast(List links, int i) { + return i == links.size() - 2; + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompiler.java new file mode 100644 index 00000000..5644ee22 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PointToPointIntentCompiler.java @@ -0,0 +1,104 @@ +/* + * Copyright 2014-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.intent.impl.compiler; + +import org.apache.felix.scr.annotations.Activate; +import org.apache.felix.scr.annotations.Component; +import org.apache.felix.scr.annotations.Deactivate; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DefaultPath; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.PathIntent; +import org.onosproject.net.intent.PointToPointIntent; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.net.resource.link.LinkResourceAllocations; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import static java.util.Arrays.asList; +import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; + +/** + * An intent compiler for {@link org.onosproject.net.intent.PointToPointIntent}. + */ +@Component(immediate = true) +public class PointToPointIntentCompiler + extends ConnectivityIntentCompiler { + + // TODO: use off-the-shell core provider ID + private static final ProviderId PID = + new ProviderId("core", "org.onosproject.core", true); + // TODO: consider whether the default cost is appropriate or not + public static final int DEFAULT_COST = 1; + + @Activate + public void activate() { + intentManager.registerCompiler(PointToPointIntent.class, this); + } + + @Deactivate + public void deactivate() { + intentManager.unregisterCompiler(PointToPointIntent.class); + } + + @Override + public List compile(PointToPointIntent intent, List installable, + Set resources) { + + ConnectPoint ingressPoint = intent.ingressPoint(); + ConnectPoint egressPoint = intent.egressPoint(); + + if (ingressPoint.deviceId().equals(egressPoint.deviceId())) { + List links = asList(createEdgeLink(ingressPoint, true), createEdgeLink(egressPoint, false)); + return asList(createPathIntent(new DefaultPath(PID, links, DEFAULT_COST), intent)); + } + + List links = new ArrayList<>(); + Path path = getPath(intent, ingressPoint.deviceId(), + egressPoint.deviceId()); + + links.add(createEdgeLink(ingressPoint, true)); + links.addAll(path.links()); + links.add(createEdgeLink(egressPoint, false)); + + return asList(createPathIntent(new DefaultPath(PID, links, path.cost(), + path.annotations()), intent)); + } + + /** + * Creates a path intent from the specified path and original + * connectivity intent. + * + * @param path path to create an intent for + * @param intent original intent + */ + private Intent createPathIntent(Path path, + PointToPointIntent intent) { + return PathIntent.builder() + .appId(intent.appId()) + .selector(intent.selector()) + .treatment(intent.treatment()) + .path(path) + .constraints(intent.constraints()) + .priority(intent.priority()) + .build(); + } + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/SinglePointToMultiPointIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/SinglePointToMultiPointIntentCompiler.java new file mode 100644 index 00000000..56565908 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/SinglePointToMultiPointIntentCompiler.java @@ -0,0 +1,85 @@ +/* + * Copyright 2014-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.intent.impl.compiler; + +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.onosproject.net.ConnectPoint; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.LinkCollectionIntent; +import org.onosproject.net.intent.SinglePointToMultiPointIntent; +import org.onosproject.net.provider.ProviderId; +import org.onosproject.net.resource.link.LinkResourceAllocations; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Component(immediate = true) +public class SinglePointToMultiPointIntentCompiler + extends ConnectivityIntentCompiler { + + // TODO: use off-the-shell core provider ID + private static final ProviderId PID = + new ProviderId("core", "org.onosproject.core", true); + + @Activate + public void activate() { + intentManager.registerCompiler(SinglePointToMultiPointIntent.class, + this); + } + + @Deactivate + public void deactivate() { + intentManager.unregisterCompiler(SinglePointToMultiPointIntent.class); + } + + + @Override + public List compile(SinglePointToMultiPointIntent intent, + List installable, + Set resources) { + Set links = new HashSet<>(); + + for (ConnectPoint egressPoint : intent.egressPoints()) { + if (egressPoint.deviceId().equals(intent.ingressPoint().deviceId())) { + continue; + } + + Path path = getPath(intent, intent.ingressPoint().deviceId(), egressPoint.deviceId()); + links.addAll(path.links()); + } + + Intent result = LinkCollectionIntent.builder() + .appId(intent.appId()) + .key(intent.key()) + .selector(intent.selector()) + .treatment(intent.treatment()) + .links(links) + .ingressPoints(ImmutableSet.of(intent.ingressPoint())) + .egressPoints(intent.egressPoints()) + .priority(intent.priority()) + .constraints(intent.constraints()) + .build(); + + return Collections.singletonList(result); + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/TwoWayP2PIntentCompiler.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/TwoWayP2PIntentCompiler.java new file mode 100644 index 00000000..50a67546 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/TwoWayP2PIntentCompiler.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.intent.impl.compiler; + +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; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.PointToPointIntent; +import org.onosproject.net.intent.TwoWayP2PIntent; +import org.onosproject.net.resource.link.LinkResourceAllocations; + +import java.util.List; +import java.util.Set; + +/** + * A intent compiler for {@link org.onosproject.net.intent.TwoWayP2PIntent}. + */ +@Component(immediate = true) +public class TwoWayP2PIntentCompiler + extends ConnectivityIntentCompiler { + + @Activate + public void activate() { + intentManager.registerCompiler(TwoWayP2PIntent.class, this); + } + + @Deactivate + public void deactivate() { + intentManager.unregisterCompiler(TwoWayP2PIntent.class); + } + + @Override + public List compile(TwoWayP2PIntent intent, List installable, + Set resources) { + return Lists.newArrayList( + PointToPointIntent.builder() + .appId(intent.appId()) + .key(intent.key()) + .selector(intent.selector()) + .treatment(intent.treatment()) + .ingressPoint(intent.one()) + .egressPoint(intent.two()) + .constraints(intent.constraints()) + .priority(intent.priority()) + .build(), + PointToPointIntent.builder() + .appId(intent.appId()) + .key(intent.key()) + .selector(intent.selector()) + .treatment(intent.treatment()) + .ingressPoint(intent.two()) + .egressPoint(intent.one()) + .constraints(intent.constraints()) + .priority(intent.priority()) + .build()); + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/package-info.java new file mode 100644 index 00000000..beaf5ed0 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/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. + */ + +/** + * Implementations of builtin intent compilers. + */ +package org.onosproject.net.intent.impl.compiler; \ No newline at end of file diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/package-info.java new file mode 100644 index 00000000..8c516c64 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2014 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. + */ + +/** + * Core subsystem for tracking high-level intents for treatment of selected + * network traffic. + */ +package org.onosproject.net.intent.impl; diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Compiling.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Compiling.java new file mode 100644 index 00000000..5078b5dc --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Compiling.java @@ -0,0 +1,73 @@ +/* + * 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.intent.impl.phase; + +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentData; +import org.onosproject.net.intent.IntentException; +import org.onosproject.net.intent.impl.IntentProcessor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Represents a phase where an intent is being compiled or recompiled. + */ +class Compiling implements IntentProcessPhase { + + private static final Logger log = LoggerFactory.getLogger(Compiling.class); + + private final IntentProcessor processor; + private final IntentData data; + private final Optional stored; + + /** + * Creates a intent recompiling phase. + * + * @param processor intent processor that does work for recompiling + * @param data intent data containing an intent to be recompiled + * @param stored intent data stored in the store + */ + Compiling(IntentProcessor processor, IntentData data, Optional stored) { + this.processor = checkNotNull(processor); + this.data = checkNotNull(data); + this.stored = checkNotNull(stored); + } + + @Override + public Optional execute() { + try { + List compiled = processor.compile(data.intent(), + //TODO consider passing an optional here in the future + stored.isPresent() ? stored.get().installables() : null); + data.setInstallables(compiled); + return Optional.of(new Installing(processor, data, stored)); + } catch (IntentException e) { + log.debug("Unable to compile intent {} due to: {}", data.intent(), e); + if (stored.isPresent() && !stored.get().installables().isEmpty()) { + // removing orphaned flows and deallocating resources + data.setInstallables(stored.get().installables()); + return Optional.of(new Withdrawing(processor, data)); + } else { + return Optional.of(new Failed(data)); + } + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Corrupt.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Corrupt.java new file mode 100644 index 00000000..2fbe1641 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Corrupt.java @@ -0,0 +1,44 @@ +/* + * 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.intent.impl.phase; + +import org.onosproject.net.intent.IntentData; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.intent.IntentState.CORRUPT; + +/** + * A class representing errors removing or installing intents. + */ +public class Corrupt extends FinalIntentProcessPhase { + + private final IntentData intentData; + + /** + * Create an instance with the specified data. + * + * @param intentData intentData + */ + Corrupt(IntentData intentData) { + this.intentData = checkNotNull(intentData); + this.intentData.setState(CORRUPT); + } + + @Override + public IntentData data() { + return intentData; + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Failed.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Failed.java new file mode 100644 index 00000000..7f628e3c --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Failed.java @@ -0,0 +1,44 @@ +/* + * 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.intent.impl.phase; + +import org.onosproject.net.intent.IntentData; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.intent.IntentState.FAILED; + +/** + * Represents a phase where the compile has failed. + */ +public class Failed extends FinalIntentProcessPhase { + + private final IntentData intentData; + + /** + * Create an instance with the specified data. + * + * @param intentData intentData + */ + Failed(IntentData intentData) { + this.intentData = checkNotNull(intentData); + this.intentData.setState(FAILED); + } + + @Override + public IntentData data() { + return intentData; + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/FinalIntentProcessPhase.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/FinalIntentProcessPhase.java new file mode 100644 index 00000000..c67b93b5 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/FinalIntentProcessPhase.java @@ -0,0 +1,44 @@ +/* + * 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.intent.impl.phase; + +import org.onosproject.net.intent.IntentData; + +import java.util.Optional; + +/** + * Represents a final phase of processing an intent. + */ +public abstract class FinalIntentProcessPhase implements IntentProcessPhase { + + @Override + public final Optional execute() { + preExecute(); + return Optional.empty(); + } + + /** + * Executes operations that must take place before the phase starts. + */ + protected void preExecute() {} + + /** + * Returns the IntentData object being acted on by this phase. + * + * @return intent data object for the phase + */ + public abstract IntentData data(); +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallRequest.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallRequest.java new file mode 100644 index 00000000..a75d7cc8 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/InstallRequest.java @@ -0,0 +1,55 @@ +/* + * 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.intent.impl.phase; + +import org.onosproject.net.intent.IntentData; +import org.onosproject.net.intent.impl.IntentProcessor; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.transferErrorCount; + +/** + * Represents a phase where intent installation has been requested. + */ +final class InstallRequest implements IntentProcessPhase { + + private final IntentProcessor processor; + private final IntentData data; + private final Optional stored; + + /** + * Creates an install request phase. + * + * @param processor intent processor to be passed to intent process phases + * generated after this phase + * @param intentData intent data to be processed + * @param stored intent data stored in the store + */ + InstallRequest(IntentProcessor processor, IntentData intentData, Optional stored) { + this.processor = checkNotNull(processor); + this.data = checkNotNull(intentData); + this.stored = checkNotNull(stored); + } + + @Override + public Optional execute() { + transferErrorCount(data, stored); + + return Optional.of(new Compiling(processor, data, stored)); + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Installing.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Installing.java new file mode 100644 index 00000000..2ff7ca8b --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Installing.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.intent.impl.phase; + +import org.onosproject.net.intent.IntentData; +import org.onosproject.net.intent.impl.IntentProcessor; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.intent.IntentState.INSTALLING; + +/** + * Represents a phase where an intent is being installed. + */ +class Installing extends FinalIntentProcessPhase { + + private final IntentProcessor processor; + private final IntentData data; + private final Optional stored; + + /** + * Create an installing phase. + * + * @param processor intent processor that does work for installing + * @param data intent data containing an intent to be installed + * @param stored intent data already stored + */ + Installing(IntentProcessor processor, IntentData data, Optional stored) { + this.processor = checkNotNull(processor); + this.data = checkNotNull(data); + this.stored = checkNotNull(stored); + this.data.setState(INSTALLING); + } + + @Override + public void preExecute() { + processor.apply(stored, Optional.of(data)); + } + + @Override + public IntentData data() { + return data; + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/IntentProcessPhase.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/IntentProcessPhase.java new file mode 100644 index 00000000..bce572c6 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/IntentProcessPhase.java @@ -0,0 +1,73 @@ +/* + * 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.intent.impl.phase; + +import org.onosproject.net.intent.IntentData; +import org.onosproject.net.intent.impl.IntentProcessor; + +import java.util.Objects; +import java.util.Optional; + +/** + * Represents a phase of processing an intent. + */ +public interface IntentProcessPhase { + + /** + * Execute the procedure represented by the instance + * and generates the next update instance. + * + * @return next update + */ + Optional execute(); + + /** + * Create a starting intent process phase according to intent data this class holds. + * + * @param processor intent processor to be passed to intent process phases + * generated while this instance is working + * @param data intent data to be processed + * @param current intent date that is stored in the store + * @return starting intent process phase + */ + static IntentProcessPhase newInitialPhase(IntentProcessor processor, + IntentData data, IntentData current) { + switch (data.request()) { + case INSTALL_REQ: + return new InstallRequest(processor, data, Optional.ofNullable(current)); + case WITHDRAW_REQ: + return new WithdrawRequest(processor, data, Optional.ofNullable(current)); + case PURGE_REQ: + return new PurgeRequest(data, Optional.ofNullable(current)); + default: + // illegal state + return new Failed(data); + } + } + + static void transferErrorCount(IntentData data, Optional stored) { + if (stored.isPresent()) { + IntentData storedData = stored.get(); + if (Objects.equals(data.intent(), storedData.intent()) && + Objects.equals(data.request(), storedData.request())) { + data.setErrorCount(storedData.errorCount()); + } else { + data.setErrorCount(0); + } + } + } + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/IntentWorker.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/IntentWorker.java new file mode 100644 index 00000000..9ddcf40e --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/IntentWorker.java @@ -0,0 +1,52 @@ +/* + * 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.intent.impl.phase; + + +import java.util.Optional; +import java.util.concurrent.Callable; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Worker to process a submitted intent. {@link #call()} method generates + */ +public final class IntentWorker implements Callable { + + private final IntentProcessPhase initial; + + /** + * Create an instance with the specified arguments. + * + * @param initial initial intent process phase + */ + public IntentWorker(IntentProcessPhase initial) { + this.initial = checkNotNull(initial); + } + + @Override + public FinalIntentProcessPhase call() throws Exception { + IntentProcessPhase update = initial; + Optional currentPhase = Optional.of(update); + IntentProcessPhase previousPhase = update; + + while (currentPhase.isPresent()) { + previousPhase = currentPhase.get(); + currentPhase = previousPhase.execute(); + } + return (FinalIntentProcessPhase) previousPhase; + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/PurgeRequest.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/PurgeRequest.java new file mode 100644 index 00000000..69126dfb --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/PurgeRequest.java @@ -0,0 +1,70 @@ +/* + * 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.intent.impl.phase; + +import org.onosproject.net.intent.IntentData; +import org.onosproject.net.intent.IntentState; +import org.slf4j.Logger; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Represents a phase of requesting a purge of an intent. + *

+ * Note: The purge will only succeed if the intent is FAILED or WITHDRAWN. + *

+ */ +final class PurgeRequest extends FinalIntentProcessPhase { + + private static final Logger log = getLogger(PurgeRequest.class); + + private final IntentData data; + private final Optional stored; + + PurgeRequest(IntentData intentData, Optional stored) { + this.data = checkNotNull(intentData); + this.stored = checkNotNull(stored); + } + + private boolean shouldAcceptPurge() { + if (!stored.isPresent()) { + log.info("Purge for intent {}, but intent is not present", + data.key()); + return true; + } + + IntentData storedData = stored.get(); + if (storedData.state() == IntentState.WITHDRAWN + || storedData.state() == IntentState.FAILED) { + return true; + } + log.info("Purge for intent {} is rejected because intent state is {}", + data.key(), storedData.state()); + return false; + } + + @Override + public IntentData data() { + if (shouldAcceptPurge()) { + return data; + } else { + return stored.get(); + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawRequest.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawRequest.java new file mode 100644 index 00000000..8a0709e6 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/WithdrawRequest.java @@ -0,0 +1,70 @@ +/* + * 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.intent.impl.phase; + +import org.onosproject.net.intent.IntentData; +import org.onosproject.net.intent.impl.IntentProcessor; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.transferErrorCount; + +/** + * Represents a phase of requesting a withdraw of an intent. + */ +final class WithdrawRequest implements IntentProcessPhase { + + private final IntentProcessor processor; + private final IntentData data; + private final Optional stored; + + /** + * Creates a withdraw request phase. + * + * @param processor intent processor to be passed to intent process phases + * generated after this phase + * @param intentData intent data to be processed + * @param stored intent data stored in the store + */ + WithdrawRequest(IntentProcessor processor, IntentData intentData, Optional stored) { + this.processor = checkNotNull(processor); + this.data = checkNotNull(intentData); + this.stored = checkNotNull(stored); + } + + @Override + public Optional execute() { + //TODO perhaps we want to validate that the pending and current are the + // same version i.e. they are the same + // Note: this call is not just the symmetric version of submit + + transferErrorCount(data, stored); + + if (!stored.isPresent() || stored.get().installables().isEmpty()) { + switch (data.request()) { + case INSTALL_REQ: + return Optional.of(new Failed(data)); + case WITHDRAW_REQ: + default: //TODO "default" case should not happen + return Optional.of(new Withdrawn(data)); + } + } + + data.setInstallables(stored.get().installables()); + return Optional.of(new Withdrawing(processor, data)); + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawing.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawing.java new file mode 100644 index 00000000..29bc4711 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawing.java @@ -0,0 +1,55 @@ +/* + * 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.intent.impl.phase; + +import org.onosproject.net.intent.IntentData; +import org.onosproject.net.intent.impl.IntentProcessor; + +import java.util.Optional; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.intent.IntentState.WITHDRAWING; + +/** + * Represents a phase where an intent is withdrawing. + */ +class Withdrawing extends FinalIntentProcessPhase { + + private final IntentProcessor processor; + private final IntentData data; + + /** + * Creates a withdrawing phase. + * + * @param processor intent processor that does work for withdrawing + * @param data intent data containing an intent to be withdrawn + */ + Withdrawing(IntentProcessor processor, IntentData data) { + this.processor = checkNotNull(processor); + this.data = checkNotNull(data); + this.data.setState(WITHDRAWING); + } + + @Override + protected void preExecute() { + processor.apply(Optional.of(data), Optional.empty()); + } + + @Override + public IntentData data() { + return data; + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawn.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawn.java new file mode 100644 index 00000000..264f74c6 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/Withdrawn.java @@ -0,0 +1,44 @@ +/* + * 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.intent.impl.phase; + +import org.onosproject.net.intent.IntentData; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onosproject.net.intent.IntentState.WITHDRAWN; + +/** + * Represents a phase where an intent has been withdrawn. + */ +final class Withdrawn extends FinalIntentProcessPhase { + + private final IntentData data; + + /** + * Create a withdrawn phase. + * + * @param data intent data containing an intent to be withdrawn + */ + Withdrawn(IntentData data) { + this.data = checkNotNull(data); + this.data.setState(WITHDRAWN); + } + + @Override + public IntentData data() { + return data; + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/package-info.java new file mode 100644 index 00000000..56e54308 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/intent/impl/phase/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. + */ + +/** + * Implementations of various intent processing phases. + */ +package org.onosproject.net.intent.impl.phase; \ No newline at end of file diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/BasicLinkOperator.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/BasicLinkOperator.java new file mode 100644 index 00000000..a6b08f62 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/BasicLinkOperator.java @@ -0,0 +1,86 @@ +/* + * Copyright 2014-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.link.impl; + +import static org.slf4j.LoggerFactory.getLogger; + +import java.time.Duration; + +import org.onosproject.net.AnnotationKeys; +import org.onosproject.net.config.ConfigOperator; +import org.onosproject.net.config.basics.BasicLinkConfig; +import org.onosproject.net.DefaultAnnotations; +import org.onosproject.net.Link; +import org.onosproject.net.SparseAnnotations; +import org.onosproject.net.link.DefaultLinkDescription; +import org.onosproject.net.link.LinkDescription; +import org.slf4j.Logger; + +/** + * Implementations of merge policies for various sources of link configuration + * information. This includes applications, provides, and network configurations. + */ +public final class BasicLinkOperator implements ConfigOperator { + + private static final long DEF_BANDWIDTH = -1L; + private static final Duration DEF_DURATION = Duration.ofNanos(-1L); + private static final Logger log = getLogger(BasicLinkOperator.class); + + private BasicLinkOperator() { + } + + /** + * Generates a LinkDescription containing fields from a LinkDescription and + * a LinkConfig. + * + * @param cfg the link config entity from network config + * @param descr a LinkDescription + * @return LinkDescription based on both sources + */ + public static LinkDescription combine(BasicLinkConfig cfg, LinkDescription descr) { + if (cfg == null) { + return descr; + } + + // cfg.type() defaults to DIRECT, so there is a risk of unwanted override. + // do we want this behavior? + Link.Type type = descr.type(); + if (cfg.type() != type) { + type = cfg.type(); + } + + SparseAnnotations sa = combine(cfg, descr.annotations()); + return new DefaultLinkDescription(descr.src(), descr.dst(), type, sa); + } + + /** + * Generates an annotation from an existing annotation and LinkConfig. + * + * @param cfg the link config entity from network config + * @param an the annotation + * @return annotation combining both sources + */ + public static SparseAnnotations combine(BasicLinkConfig cfg, SparseAnnotations an) { + DefaultAnnotations.Builder b = DefaultAnnotations.builder(); + if (cfg.latency() != DEF_DURATION) { + b.set(AnnotationKeys.LATENCY, cfg.latency().toString()); + } + if (cfg.bandwidth() != DEF_BANDWIDTH) { + b.set(AnnotationKeys.BANDWIDTH, String.valueOf(cfg.bandwidth())); + } + return DefaultAnnotations.union(an, b.build()); + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java new file mode 100644 index 00000000..157288a4 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/LinkManager.java @@ -0,0 +1,343 @@ +/* + * Copyright 2014 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.link.impl; + +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +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; +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.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.BasicLinkConfig; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Link.State; +import org.onosproject.net.LinkKey; +import org.onosproject.net.MastershipRole; +import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceListener; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.link.LinkAdminService; +import org.onosproject.net.link.LinkDescription; +import org.onosproject.net.link.LinkEvent; +import org.onosproject.net.link.LinkListener; +import org.onosproject.net.link.LinkProvider; +import org.onosproject.net.link.LinkProviderRegistry; +import org.onosproject.net.link.LinkProviderService; +import org.onosproject.net.link.LinkService; +import org.onosproject.net.link.LinkStore; +import org.onosproject.net.link.LinkStoreDelegate; +import org.onosproject.net.provider.AbstractProviderService; +import org.slf4j.Logger; + +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static org.onosproject.net.LinkKey.linkKey; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.slf4j.LoggerFactory.getLogger; +import static org.onosproject.security.AppPermission.Type.*; + + +/** + * Provides basic implementation of the link SB & NB APIs. + */ +@Component(immediate = true) +@Service +public class LinkManager + extends AbstractListenerProviderRegistry + implements LinkService, LinkAdminService, LinkProviderRegistry { + + private static final String DEVICE_ID_NULL = "Device ID cannot be null"; + private static final String LINK_DESC_NULL = "Link description cannot be null"; + private static final String CONNECT_POINT_NULL = "Connection point cannot be null"; + + private final Logger log = getLogger(getClass()); + + private final LinkStoreDelegate delegate = new InternalStoreDelegate(); + + private final DeviceListener deviceListener = new InternalDeviceListener(); + + private final NetworkConfigListener networkConfigListener = new InternalNetworkConfigListener(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LinkStore store; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected NetworkConfigService networkConfigService; + + @Activate + public void activate() { + store.setDelegate(delegate); + eventDispatcher.addSink(LinkEvent.class, listenerRegistry); + deviceService.addListener(deviceListener); + networkConfigService.addListener(networkConfigListener); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + store.unsetDelegate(delegate); + eventDispatcher.removeSink(LinkEvent.class); + deviceService.removeListener(deviceListener); + networkConfigService.removeListener(networkConfigListener); + log.info("Stopped"); + } + + @Override + public int getLinkCount() { + checkPermission(LINK_READ); + return store.getLinkCount(); + } + + @Override + public Iterable getLinks() { + checkPermission(LINK_READ); + return store.getLinks(); + } + + @Override + public Iterable getActiveLinks() { + checkPermission(LINK_READ); + return FluentIterable.from(getLinks()) + .filter(new Predicate() { + + @Override + public boolean apply(Link input) { + return input.state() == State.ACTIVE; + } + }); + } + + @Override + public Set getDeviceLinks(DeviceId deviceId) { + checkPermission(LINK_READ); + checkNotNull(deviceId, DEVICE_ID_NULL); + return Sets.union(store.getDeviceEgressLinks(deviceId), + store.getDeviceIngressLinks(deviceId)); + } + + @Override + public Set getDeviceEgressLinks(DeviceId deviceId) { + checkPermission(LINK_READ); + checkNotNull(deviceId, DEVICE_ID_NULL); + return store.getDeviceEgressLinks(deviceId); + } + + @Override + public Set getDeviceIngressLinks(DeviceId deviceId) { + checkPermission(LINK_READ); + checkNotNull(deviceId, DEVICE_ID_NULL); + return store.getDeviceIngressLinks(deviceId); + } + + @Override + public Set getLinks(ConnectPoint connectPoint) { + checkPermission(LINK_READ); + checkNotNull(connectPoint, CONNECT_POINT_NULL); + return Sets.union(store.getEgressLinks(connectPoint), + store.getIngressLinks(connectPoint)); + } + + @Override + public Set getEgressLinks(ConnectPoint connectPoint) { + checkPermission(LINK_READ); + checkNotNull(connectPoint, CONNECT_POINT_NULL); + return store.getEgressLinks(connectPoint); + } + + @Override + public Set getIngressLinks(ConnectPoint connectPoint) { + checkPermission(LINK_READ); + checkNotNull(connectPoint, CONNECT_POINT_NULL); + return store.getIngressLinks(connectPoint); + } + + @Override + public Link getLink(ConnectPoint src, ConnectPoint dst) { + checkPermission(LINK_READ); + checkNotNull(src, CONNECT_POINT_NULL); + checkNotNull(dst, CONNECT_POINT_NULL); + return store.getLink(src, dst); + } + + @Override + public void removeLinks(ConnectPoint connectPoint) { + if (deviceService.getRole(connectPoint.deviceId()) != MastershipRole.MASTER) { + return; + } + removeLinks(getLinks(connectPoint), false); + } + + @Override + public void removeLinks(DeviceId deviceId) { + if (deviceService.getRole(deviceId) != MastershipRole.MASTER) { + return; + } + removeLinks(getDeviceLinks(deviceId), false); + } + + @Override + public void removeLink(ConnectPoint src, ConnectPoint dst) { + post(store.removeLink(src, dst)); + } + + // Auxiliary interceptor for device remove events to prune links that + // are associated with the removed device or its port. + private class InternalDeviceListener implements DeviceListener { + @Override + public void event(DeviceEvent event) { + if (event.type() == DeviceEvent.Type.DEVICE_REMOVED) { + removeLinks(event.subject().id()); + } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) { + removeLinks(new ConnectPoint(event.subject().id(), + event.port().number())); + } + } + } + + @Override + protected LinkProviderService createProviderService(LinkProvider provider) { + return new InternalLinkProviderService(provider); + } + + // Personalized link provider service issued to the supplied provider. + private class InternalLinkProviderService + extends AbstractProviderService + implements LinkProviderService { + + InternalLinkProviderService(LinkProvider provider) { + super(provider); + } + + @Override + public void linkDetected(LinkDescription linkDescription) { + checkNotNull(linkDescription, LINK_DESC_NULL); + checkValidity(); + linkDescription = validateLink(linkDescription); + LinkEvent event = store.createOrUpdateLink(provider().id(), + linkDescription); + if (event != null) { + log.info("Link {} detected", linkDescription); + post(event); + } + } + + // returns a LinkDescription made from the union of the BasicLinkConfig + // annotations if it exists + private LinkDescription validateLink(LinkDescription linkDescription) { + // TODO Investigate whether this can be made more efficient + BasicLinkConfig cfg = networkConfigService.getConfig(linkKey(linkDescription.src(), + linkDescription.dst()), + BasicLinkConfig.class); + BasicLinkConfig cfgTwo = networkConfigService.getConfig(linkKey(linkDescription.dst(), + linkDescription.src()), + BasicLinkConfig.class); + + checkState(cfg == null || cfg.isAllowed(), "Link " + linkDescription.toString() + " is not allowed"); + checkState(cfgTwo == null || cfgTwo.isAllowed(), "Link " + linkDescription.toString() + " is not allowed"); + + return BasicLinkOperator.combine(cfg, linkDescription); + } + + @Override + public void linkVanished(LinkDescription linkDescription) { + checkNotNull(linkDescription, LINK_DESC_NULL); + checkValidity(); + + ConnectPoint src = linkDescription.src(); + ConnectPoint dst = linkDescription.dst(); + + LinkEvent event = store.removeOrDownLink(src, dst); + if (event != null) { + log.info("Link {} vanished", linkDescription); + post(event); + } + } + + @Override + public void linksVanished(ConnectPoint connectPoint) { + checkNotNull(connectPoint, "Connect point cannot be null"); + checkValidity(); + + log.debug("Links for connection point {} vanished", connectPoint); + // FIXME: This will remove links registered by other providers + removeLinks(getLinks(connectPoint), true); + } + + @Override + public void linksVanished(DeviceId deviceId) { + checkNotNull(deviceId, DEVICE_ID_NULL); + checkValidity(); + + log.debug("Links for device {} vanished", deviceId); + removeLinks(getDeviceLinks(deviceId), true); + } + } + + // Removes all links in the specified set and emits appropriate events. + private void removeLinks(Set links, boolean isSoftRemove) { + for (Link link : links) { + LinkEvent event = isSoftRemove ? + store.removeOrDownLink(link.src(), link.dst()) : + store.removeLink(link.src(), link.dst()); + if (event != null) { + log.info("Link {} removed/vanished", event.subject()); + post(event); + } + } + } + + // Store delegate to re-post events emitted from the store. + private class InternalStoreDelegate implements LinkStoreDelegate { + @Override + public void notify(LinkEvent event) { + post(event); + } + } + + // listens for NetworkConfigEvents of type BasicLinkConfig and removes + // links that the config does not allow + private class InternalNetworkConfigListener implements NetworkConfigListener { + @Override + public void event(NetworkConfigEvent event) { + if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED || + event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) && + event.configClass().equals(BasicLinkConfig.class)) { + log.info("Detected Link network config event {}", event.type()); + LinkKey lk = (LinkKey) event.subject(); + BasicLinkConfig cfg = networkConfigService.getConfig(lk, BasicLinkConfig.class); + if (cfg != null && !cfg.isAllowed()) { + log.info("Kicking out links between {} and {}", lk.src(), lk.dst()); + removeLink(lk.src(), lk.dst()); + removeLink(lk.dst(), lk.src()); + } + } + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/package-info.java new file mode 100644 index 00000000..4c32c3fc --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/link/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Core subsystem for tracking global inventory of infrastructure links. + */ +package org.onosproject.net.link.impl; diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceDeviceListener.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceDeviceListener.java new file mode 100644 index 00000000..e6d92253 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceDeviceListener.java @@ -0,0 +1,86 @@ +/* + * 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.newresource.impl; + +import org.onosproject.net.Device; +import org.onosproject.net.Port; +import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceListener; +import org.onosproject.net.newresource.ResourceAdminService; +import org.onosproject.net.newresource.ResourcePath; + +import java.util.concurrent.ExecutorService; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An implementation of DeviceListener registering devices as resources. + */ +final class ResourceDeviceListener implements DeviceListener { + + private final ResourceAdminService adminService; + private final ExecutorService executor; + + /** + * Creates an instance with the specified ResourceAdminService and ExecutorService. + * + * @param adminService instance invoked to register resources + * @param executor executor used for processing resource registration + */ + ResourceDeviceListener(ResourceAdminService adminService, ExecutorService executor) { + this.adminService = checkNotNull(adminService); + this.executor = checkNotNull(executor); + } + + @Override + public void event(DeviceEvent event) { + Device device = event.subject(); + switch (event.type()) { + case DEVICE_ADDED: + registerDeviceResource(device); + break; + case DEVICE_REMOVED: + unregisterDeviceResource(device); + break; + case PORT_ADDED: + registerPortResource(device, event.port()); + break; + case PORT_REMOVED: + unregisterPortResource(device, event.port()); + break; + default: + break; + } + } + + private void registerDeviceResource(Device device) { + executor.submit(() -> adminService.registerResources(ResourcePath.ROOT, device.id())); + } + + private void unregisterDeviceResource(Device device) { + executor.submit(() -> adminService.unregisterResources(ResourcePath.ROOT, device.id())); + } + + private void registerPortResource(Device device, Port port) { + ResourcePath parent = new ResourcePath(device.id()); + executor.submit(() -> adminService.registerResources(parent, port.number())); + } + + private void unregisterPortResource(Device device, Port port) { + ResourcePath parent = new ResourcePath(device.id()); + executor.submit(() -> adminService.unregisterResources(parent, port.number())); + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceLinkListener.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceLinkListener.java new file mode 100644 index 00000000..f04c78b9 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceLinkListener.java @@ -0,0 +1,152 @@ +/* + * 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.newresource.impl; + +import org.onlab.packet.MplsLabel; +import org.onlab.packet.VlanId; +import org.onlab.util.ItemNotFoundException; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Link; +import org.onosproject.net.LinkKey; +import org.onosproject.net.behaviour.MplsQuery; +import org.onosproject.net.behaviour.VlanQuery; +import org.onosproject.net.driver.DriverHandler; +import org.onosproject.net.driver.DriverService; +import org.onosproject.net.link.LinkEvent; +import org.onosproject.net.link.LinkListener; +import org.onosproject.net.newresource.ResourceAdminService; +import org.onosproject.net.newresource.ResourcePath; + +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An implementation of LinkListener registering links as resources. + */ +final class ResourceLinkListener implements LinkListener { + + private static final int TOTAL_VLANS = 1024; + private static final List ENTIRE_VLAN_IDS = getEntireVlans(); + + private static final int TOTAL_MPLS_LABELS = 1048576; + private static final List ENTIRE_MPLS_LABELS = getEntireMplsLabels(); + + private final ResourceAdminService adminService; + private final DriverService driverService; + private final ExecutorService executor; + + /** + * Creates an instance with the specified ResourceAdminService and ExecutorService. + * + * @param adminService instance invoked to register resources + * @param driverService driver service instance + * @param executor executor used for processing resource registration + */ + ResourceLinkListener(ResourceAdminService adminService, DriverService driverService, ExecutorService executor) { + this.adminService = checkNotNull(adminService); + this.driverService = checkNotNull(driverService); + this.executor = checkNotNull(executor); + } + + @Override + public void event(LinkEvent event) { + Link link = event.subject(); + switch (event.type()) { + case LINK_ADDED: + registerLinkResource(link); + break; + case LINK_REMOVED: + unregisterLinkResource(link); + break; + default: + break; + } + } + + private void registerLinkResource(Link link) { + executor.submit(() -> { + // register the link + LinkKey linkKey = LinkKey.linkKey(link); + adminService.registerResources(ResourcePath.ROOT, linkKey); + + ResourcePath linkPath = new ResourcePath(linkKey); + // register VLAN IDs against the link + if (isEnabled(link, this::isVlanEnabled)) { + adminService.registerResources(linkPath, ENTIRE_VLAN_IDS); + } + + // register MPLS labels against the link + if (isEnabled(link, this::isMplsEnabled)) { + adminService.registerResources(linkPath, ENTIRE_MPLS_LABELS); + } + }); + } + + private void unregisterLinkResource(Link link) { + LinkKey linkKey = LinkKey.linkKey(link); + executor.submit(() -> adminService.unregisterResources(ResourcePath.ROOT, linkKey)); + } + + private boolean isEnabled(Link link, Predicate predicate) { + return predicate.test(link.src()) && predicate.test(link.dst()); + } + + private boolean isVlanEnabled(ConnectPoint cp) { + try { + DriverHandler handler = driverService.createHandler(cp.deviceId()); + if (handler == null) { + return false; + } + + VlanQuery query = handler.behaviour(VlanQuery.class); + return query != null && query.isEnabled(cp.port()); + } catch (ItemNotFoundException e) { + return false; + } + } + + private boolean isMplsEnabled(ConnectPoint cp) { + try { + DriverHandler handler = driverService.createHandler(cp.deviceId()); + if (handler == null) { + return false; + } + + MplsQuery query = handler.behaviour(MplsQuery.class); + return query != null && query.isEnabled(cp.port()); + } catch (ItemNotFoundException e) { + return false; + } + } + + private static List getEntireVlans() { + return IntStream.range(0, TOTAL_VLANS) + .mapToObj(x -> VlanId.vlanId((short) x)) + .collect(Collectors.toList()); + } + + private static List getEntireMplsLabels() { + // potentially many objects are created + return IntStream.range(0, TOTAL_MPLS_LABELS) + .mapToObj(MplsLabel::mplsLabel) + .collect(Collectors.toList()); + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java new file mode 100644 index 00000000..2cd1a2e0 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java @@ -0,0 +1,148 @@ +/* + * 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.newresource.impl; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import org.apache.felix.scr.annotations.Component; +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.newresource.ResourceAdminService; +import org.onosproject.net.newresource.ResourceAllocation; +import org.onosproject.net.newresource.ResourceConsumer; +import org.onosproject.net.newresource.ResourceService; +import org.onosproject.net.newresource.ResourcePath; +import org.onosproject.net.newresource.ResourceStore; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An implementation of ResourceService. + */ +@Component(immediate = true, enabled = false) +@Service +@Beta +public final class ResourceManager implements ResourceService, ResourceAdminService { + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ResourceStore store; + + @Override + public List allocate(ResourceConsumer consumer, + List resources) { + checkNotNull(consumer); + checkNotNull(resources); + + // TODO: implement support of resource hierarchy + // allocation for a particular resource implies allocations for all of the sub-resources need to be done + + boolean success = store.allocate(resources, consumer); + if (!success) { + return ImmutableList.of(); + } + + return resources.stream() + .map(x -> new ResourceAllocation(x, consumer)) + .collect(Collectors.toList()); + } + + @Override + public boolean release(List allocations) { + checkNotNull(allocations); + + List resources = allocations.stream() + .map(ResourceAllocation::resource) + .collect(Collectors.toList()); + List consumers = allocations.stream() + .map(ResourceAllocation::consumer) + .collect(Collectors.toList()); + + return store.release(resources, consumers); + } + + @Override + public boolean release(ResourceConsumer consumer) { + checkNotNull(consumer); + + Collection allocations = getResourceAllocations(consumer); + return release(ImmutableList.copyOf(allocations)); + } + + @Override + public Collection getResourceAllocations(ResourcePath parent, Class cls) { + checkNotNull(parent); + checkNotNull(cls); + + Collection resources = store.getAllocatedResources(parent, cls); + List allocations = new ArrayList<>(resources.size()); + for (ResourcePath resource: resources) { + // We access store twice in this method, then the store may be updated by others + Optional consumer = store.getConsumer(resource); + if (consumer.isPresent()) { + allocations.add(new ResourceAllocation(resource, consumer.get())); + } + } + + return allocations; + } + + @Override + public Collection getResourceAllocations(ResourceConsumer consumer) { + checkNotNull(consumer); + + Collection resources = store.getResources(consumer); + return resources.stream() + .map(x -> new ResourceAllocation(x, consumer)) + .collect(Collectors.toList()); + } + + @Override + public boolean isAvailable(ResourcePath resource) { + checkNotNull(resource); + + Optional consumer = store.getConsumer(resource); + return !consumer.isPresent(); + } + + @Override + public boolean registerResources(ResourcePath parent, List children) { + checkNotNull(parent); + checkNotNull(children); + checkArgument(!children.isEmpty()); + + List resources = Lists.transform(children, x -> ResourcePath.child(parent, x)); + return store.register(resources); + } + + @Override + public boolean unregisterResources(ResourcePath parent, List children) { + checkNotNull(parent); + checkNotNull(children); + checkArgument(!children.isEmpty()); + + List resources = Lists.transform(children, x -> ResourcePath.child(parent, x)); + return store.unregister(resources); + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceRegistrar.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceRegistrar.java new file mode 100644 index 00000000..4067d017 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceRegistrar.java @@ -0,0 +1,73 @@ +/* + * 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.newresource.impl; + +import com.google.common.annotations.Beta; +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.onosproject.net.device.DeviceListener; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.driver.DriverService; +import org.onosproject.net.link.LinkListener; +import org.onosproject.net.link.LinkService; +import org.onosproject.net.newresource.ResourceAdminService; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import static org.onlab.util.Tools.groupedThreads; + +/** + * A class registering resources when they are detected. + */ +@Component(immediate = true, enabled = false) +@Beta +public final class ResourceRegistrar { + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ResourceAdminService adminService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DriverService driverService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LinkService linkService; + + private DeviceListener deviceListener; + private LinkListener linkListener; + private final ExecutorService executor = + Executors.newSingleThreadExecutor(groupedThreads("onos/resource", "registrar")); + + @Activate + public void activate() { + deviceListener = new ResourceDeviceListener(adminService, executor); + deviceService.addListener(deviceListener); + linkListener = new ResourceLinkListener(adminService, driverService, executor); + linkService.addListener(linkListener); + } + + @Deactivate + public void deactivate() { + deviceService.removeListener(deviceListener); + linkService.removeListener(linkListener); + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/package-info.java new file mode 100644 index 00000000..bddfdfc1 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/newresource/impl/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. + */ + +/** + * Implementation of the generic network resource subsystem. + */ +package org.onosproject.net.newresource.impl; \ No newline at end of file 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 new file mode 100644 index 00000000..75239fdd --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/PacketManager.java @@ -0,0 +1,329 @@ +/* + * Copyright 2014-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.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.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.Device; +import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceListener; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.FlowRuleService; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flowobjective.DefaultForwardingObjective; +import org.onosproject.net.flowobjective.FlowObjectiveService; +import org.onosproject.net.flowobjective.ForwardingObjective; +import org.onosproject.net.flowobjective.Objective; +import org.onosproject.net.flowobjective.ObjectiveContext; +import org.onosproject.net.flowobjective.ObjectiveError; +import org.onosproject.net.packet.DefaultPacketRequest; +import org.onosproject.net.packet.OutboundPacket; +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.PacketProvider; +import org.onosproject.net.packet.PacketProviderRegistry; +import org.onosproject.net.packet.PacketProviderService; +import org.onosproject.net.packet.PacketRequest; +import org.onosproject.net.packet.PacketService; +import org.onosproject.net.packet.PacketStore; +import org.onosproject.net.packet.PacketStoreDelegate; +import org.onosproject.net.provider.AbstractProviderRegistry; +import org.onosproject.net.provider.AbstractProviderService; +import org.slf4j.Logger; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.util.Tools.groupedThreads; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.slf4j.LoggerFactory.getLogger; +import static org.onosproject.security.AppPermission.Type.*; + +/** + * Provides a basic implementation of the packet SB & NB APIs. + */ +@Component(immediate = true) +@Service +public class PacketManager + extends AbstractProviderRegistry + implements PacketService, PacketProviderRegistry { + + private final Logger log = getLogger(getClass()); + + private static final String TABLE_TYPE_MSG = + "Table Type cannot be null. For requesting packets without " + + "table hints, use other methods in the packetService API"; + + private final PacketStoreDelegate delegate = new InternalStoreDelegate(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + private CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + private DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + private FlowRuleService flowService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + private PacketStore store; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + private FlowObjectiveService objectiveService; + + private ExecutorService eventHandlingExecutor; + + private final DeviceListener deviceListener = new InternalDeviceListener(); + + private final Map processors = new ConcurrentHashMap<>(); + + private ApplicationId appId; + + @Activate + public void activate() { + eventHandlingExecutor = Executors.newSingleThreadExecutor( + 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. + log.info("Started"); + } + + @Deactivate + public void deactivate() { + store.unsetDelegate(delegate); + deviceService.removeListener(deviceListener); + eventHandlingExecutor.shutdown(); + log.info("Stopped"); + } + + @Override + public void addProcessor(PacketProcessor processor, int priority) { + checkPermission(PACKET_EVENT); + checkNotNull(processor, "Processor cannot be null"); + processors.put(priority, processor); + } + + @Override + public void removeProcessor(PacketProcessor processor) { + checkPermission(PACKET_EVENT); + checkNotNull(processor, "Processor cannot be null"); + processors.values().remove(processor); + } + + @Override + public void requestPackets(TrafficSelector selector, PacketPriority priority, + ApplicationId appId) { + checkPermission(PACKET_READ); + checkNotNull(selector, "Selector cannot be null"); + checkNotNull(appId, "Application ID cannot be null"); + + PacketRequest request = new DefaultPacketRequest(selector, priority, appId); + if (store.requestPackets(request)) { + pushToAllDevices(request); + } + } + + @Override + public void cancelPackets(TrafficSelector selector, PacketPriority priority, + ApplicationId appId) { + checkPermission(PACKET_READ); + checkNotNull(selector, "Selector cannot be null"); + checkNotNull(appId, "Application ID cannot be null"); + + PacketRequest request = new DefaultPacketRequest(selector, priority, appId); + if (store.cancelPackets(request)) { + removeFromAllDevices(request); + } + } + + /** + * Pushes a packet request flow rule to all devices. + * + * @param request the packet request + */ + private void pushToAllDevices(PacketRequest request) { + log.debug("Pushing packet request {} to all devices", request); + for (Device device : deviceService.getDevices()) { + pushRule(device, request); + } + } + + + /** + * 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); + } + } + + /** + * Pushes packet intercept flow rules to the device. + * + * @param device the device to push the rules to + * @param request the packet request + */ + private void pushRule(Device device, PacketRequest request) { + if (!device.type().equals(Device.Type.SWITCH)) { + return; + } + + ForwardingObjective forwarding = createBuilder(request) + .add(new ObjectiveContext() { + @Override + public void onError(Objective objective, ObjectiveError error) { + log.warn("Failed to install packet request {} to {}: {}", + request, device.id(), error); + } + }); + + objectiveService.forward(device.id(), forwarding); + } + + /** + * Removes packet intercept flow rules from the device. + * + * @param device the device to remove the rules deom + * @param request the packet request + */ + private void removeRule(Device device, PacketRequest request) { + if (!device.type().equals(Device.Type.SWITCH)) { + return; + } + + ForwardingObjective forwarding = createBuilder(request) + .remove(new ObjectiveContext() { + @Override + public void onError(Objective objective, ObjectiveError error) { + log.warn("Failed to withdraw packet request {} from {}: {}", + request, device.id(), error); + } + }); + + objectiveService.forward(device.id(), forwarding); + } + + private DefaultForwardingObjective.Builder createBuilder(PacketRequest request) { + return DefaultForwardingObjective.builder() + .withPriority(request.priority().priorityValue()) + .withSelector(request.selector()) + .fromApp(appId) + .withFlag(ForwardingObjective.Flag.VERSATILE) + .withTreatment(DefaultTrafficTreatment.builder().punt().build()) + .makePermanent(); + } + + @Override + public void emit(OutboundPacket packet) { + checkPermission(PACKET_WRITE); + checkNotNull(packet, "Packet cannot be null"); + store.emit(packet); + } + + private void localEmit(OutboundPacket packet) { + final Device device = deviceService.getDevice(packet.sendThrough()); + + if (device == null) { + return; + } + + PacketProvider packetProvider = getProvider(device.providerId()); + if (packetProvider != null) { + packetProvider.emit(packet); + } + } + + @Override + protected PacketProviderService createProviderService(PacketProvider provider) { + return new InternalPacketProviderService(provider); + } + + // Personalized packet provider service issued to the supplied provider. + private class InternalPacketProviderService + extends AbstractProviderService + implements PacketProviderService { + + protected InternalPacketProviderService(PacketProvider provider) { + super(provider); + } + + @Override + public void processPacket(PacketContext context) { + // TODO filter packets sent to processors based on registrations + for (PacketProcessor processor : processors.values()) { + processor.process(context); + } + } + + } + + /** + * Internal callback from the packet store. + */ + private class InternalStoreDelegate implements PacketStoreDelegate { + @Override + public void notify(PacketEvent event) { + localEmit(event.subject()); + } + } + + /** + * Internal listener for device service events. + */ + private class InternalDeviceListener implements DeviceListener { + @Override + public void event(DeviceEvent event) { + eventHandlingExecutor.execute(() -> { + 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); + } + } + break; + default: + break; + } + } catch (Exception e) { + log.warn("Failed to process {}", event, e); + } + }); + } + } + +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/package-info.java new file mode 100644 index 00000000..f3af4850 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/packet/impl/package-info.java @@ -0,0 +1,22 @@ +/* + * Copyright 2014 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. + */ + +/** + * Core subsystem for processing inbound packets and emitting outbound packets. + * Processing of inbound packets is always in the local context only, but + * emitting outbound packets allows for cluster-wide operation. + */ +package org.onosproject.net.packet.impl; diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java new file mode 100644 index 00000000..398260ff --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/proxyarp/impl/ProxyArpManager.java @@ -0,0 +1,447 @@ +/* + * Copyright 2014-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.proxyarp.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.onlab.packet.ARP; +import org.onlab.packet.Ethernet; +import org.onlab.packet.ICMP6; +import org.onlab.packet.IPv6; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip6Address; +import org.onlab.packet.IpAddress; +import org.onlab.packet.MacAddress; +import org.onlab.packet.VlanId; +import org.onlab.packet.ndp.NeighborAdvertisement; +import org.onlab.packet.ndp.NeighborDiscoveryOptions; +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; +import org.onosproject.net.Host; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.edge.EdgePortService; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.host.HostService; +import org.onosproject.net.link.LinkService; +import org.onosproject.net.packet.DefaultOutboundPacket; +import org.onosproject.net.packet.InboundPacket; +import org.onosproject.net.packet.PacketContext; +import org.onosproject.net.packet.PacketService; +import org.onosproject.net.proxyarp.ProxyArpService; +import org.onosproject.net.proxyarp.ProxyArpStore; +import org.slf4j.Logger; + +import java.nio.ByteBuffer; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.onlab.packet.VlanId.vlanId; +import static org.onosproject.net.HostId.hostId; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.slf4j.LoggerFactory.getLogger; +import static org.onosproject.security.AppPermission.Type.*; + + +@Component(immediate = true) +@Service +public class ProxyArpManager implements ProxyArpService { + + private final Logger log = getLogger(getClass()); + + private static final String MAC_ADDR_NULL = "Mac address cannot be null."; + private static final String REQUEST_NULL = "ARP or NDP request cannot be null."; + private static final String REQUEST_NOT_ARP = "Ethernet frame does not contain ARP request."; + private static final String NOT_ARP_REQUEST = "ARP is not a request."; + private static final String NOT_ARP_REPLY = "ARP is not a reply."; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected EdgePortService edgeService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected HostService hostService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected PacketService packetService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LinkService linkService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ProxyArpStore store; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected InterfaceService interfaceService; + + @Activate + public void activate() { + store.setDelegate(this::sendTo); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + store.setDelegate(null); + log.info("Stopped"); + } + + @Override + public boolean isKnown(IpAddress addr) { + checkPermission(PACKET_READ); + + checkNotNull(addr, MAC_ADDR_NULL); + Set hosts = hostService.getHostsByIp(addr); + return !hosts.isEmpty(); + } + + @Override + public void reply(Ethernet eth, ConnectPoint inPort) { + checkPermission(PACKET_WRITE); + + checkNotNull(eth, REQUEST_NULL); + + if (eth.getEtherType() == Ethernet.TYPE_ARP) { + replyArp(eth, inPort); + } else if (eth.getEtherType() == Ethernet.TYPE_IPV6) { + replyNdp(eth, inPort); + } + } + + private void replyArp(Ethernet eth, ConnectPoint inPort) { + ARP arp = (ARP) eth.getPayload(); + checkArgument(arp.getOpCode() == ARP.OP_REQUEST, NOT_ARP_REQUEST); + checkNotNull(inPort); + Ip4Address targetAddress = Ip4Address.valueOf(arp.getTargetProtocolAddress()); + + VlanId vlan = vlanId(eth.getVlanID()); + + if (hasIpAddress(inPort)) { + // If the request came from outside the network, only reply if it was + // for one of our external addresses. + + interfaceService.getInterfacesByPort(inPort) + .stream() + .filter(intf -> intf.ipAddresses() + .stream() + .anyMatch(ia -> ia.ipAddress().equals(targetAddress))) + .forEach(intf -> buildAndSendArp(targetAddress, intf.mac(), eth, inPort)); + + // Stop here and don't proxy ARPs if the port has an IP address + return; + } + + // See if we have the target host in the host store + + Set hosts = hostService.getHostsByIp(targetAddress); + + Host dst = null; + Host src = hostService.getHost(hostId(eth.getSourceMAC(), + vlanId(eth.getVlanID()))); + + for (Host host : hosts) { + if (host.vlan().equals(vlan)) { + dst = host; + break; + } + } + + if (src != null && dst != null) { + // We know the target host so we can respond + buildAndSendArp(targetAddress, dst.mac(), eth, inPort); + return; + } + + // If the source address matches one of our external addresses + // it could be a request from an internal host to an external + // address. Forward it over to the correct port. + Ip4Address source = + Ip4Address.valueOf(arp.getSenderProtocolAddress()); + + boolean matched = false; + Set interfaces = interfaceService.getInterfacesByIp(source); + for (Interface intf : interfaces) { + if (intf.vlan().equals(vlan)) { + matched = true; + sendTo(eth, intf.connectPoint()); + break; + } + } + + if (matched) { + return; + } + + // The request couldn't be resolved. + // Flood the request on all ports except the incoming port. + flood(eth, inPort); + } + + private void replyNdp(Ethernet eth, ConnectPoint inPort) { + IPv6 ipv6 = (IPv6) eth.getPayload(); + ICMP6 icmpv6 = (ICMP6) ipv6.getPayload(); + NeighborSolicitation nsol = (NeighborSolicitation) icmpv6.getPayload(); + Ip6Address targetAddress = Ip6Address.valueOf(nsol.getTargetAddress()); + + VlanId vlan = vlanId(eth.getVlanID()); + + // If the request came from outside the network, only reply if it was + // for one of our external addresses. + if (hasIpAddress(inPort)) { + interfaceService.getInterfacesByPort(inPort) + .stream() + .filter(intf -> intf.ipAddresses() + .stream() + .anyMatch(ia -> ia.ipAddress().equals(targetAddress))) + .forEach(intf -> buildAndSendNdp(targetAddress, intf.mac(), eth, inPort)); + return; + } + + // Continue with normal proxy ARP case + + Set hosts = hostService.getHostsByIp(targetAddress); + + Host dst = null; + Host src = hostService.getHost(hostId(eth.getSourceMAC(), + vlanId(eth.getVlanID()))); + + for (Host host : hosts) { + if (host.vlan().equals(vlan)) { + dst = host; + break; + } + } + + if (src != null && dst != null) { + // We know the target host so we can respond + buildAndSendNdp(targetAddress, dst.mac(), eth, inPort); + return; + } + + // If the source address matches one of our external addresses + // it could be a request from an internal host to an external + // address. Forward it over to the correct port. + Ip6Address source = + Ip6Address.valueOf(ipv6.getSourceAddress()); + + boolean matched = false; + + Set interfaces = interfaceService.getInterfacesByIp(source); + for (Interface intf : interfaces) { + if (intf.vlan().equals(vlan)) { + matched = true; + sendTo(eth, intf.connectPoint()); + break; + } + } + + if (matched) { + return; + } + + // The request couldn't be resolved. + // Flood the request on all ports except the incoming ports. + flood(eth, inPort); + } + //TODO checkpoint + + private void buildAndSendArp(Ip4Address srcIp, MacAddress srcMac, + Ethernet request, ConnectPoint port) { + sendTo(ARP.buildArpReply(srcIp, srcMac, request), port); + } + + private void buildAndSendNdp(Ip6Address srcIp, MacAddress srcMac, + Ethernet request, ConnectPoint port) { + sendTo(buildNdpReply(srcIp, srcMac, request), port); + } + + /** + * Outputs the given packet out the given port. + * + * @param packet the packet to send + * @param outPort the port to send it out + */ + private void sendTo(Ethernet packet, ConnectPoint outPort) { + sendTo(outPort, ByteBuffer.wrap(packet.serialize())); + } + + private void sendTo(ConnectPoint outPort, ByteBuffer packet) { + if (!edgeService.isEdgePoint(outPort)) { + // Sanity check to make sure we don't send the packet out an + // internal port and create a loop (could happen due to + // misconfiguration). + return; + } + + TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); + builder.setOutput(outPort.port()); + packetService.emit(new DefaultOutboundPacket(outPort.deviceId(), + builder.build(), packet)); + } + + /** + * Returns whether the given port has any IP addresses configured or not. + * + * @param port the port to check + * @return true if the port has at least one IP address configured, + * otherwise false + */ + private boolean hasIpAddress(ConnectPoint port) { + return interfaceService.getInterfacesByPort(port) + .stream() + .map(intf -> intf.ipAddresses()) + .findAny() + .isPresent(); + } + + @Override + public void forward(Ethernet eth, ConnectPoint inPort) { + checkPermission(PACKET_WRITE); + + checkNotNull(eth, REQUEST_NULL); + + Host h = hostService.getHost(hostId(eth.getDestinationMAC(), + vlanId(eth.getVlanID()))); + + if (h == null) { + flood(eth, inPort); + } else { + Host subject = hostService.getHost(hostId(eth.getSourceMAC(), + vlanId(eth.getVlanID()))); + store.forward(h.location(), subject, ByteBuffer.wrap(eth.serialize())); + } + } + + @Override + public boolean handlePacket(PacketContext context) { + checkPermission(PACKET_WRITE); + + InboundPacket pkt = context.inPacket(); + Ethernet ethPkt = pkt.parsed(); + + if (ethPkt == null) { + return false; + } + if (ethPkt.getEtherType() == Ethernet.TYPE_ARP) { + return handleArp(context, ethPkt); + } else if (ethPkt.getEtherType() == Ethernet.TYPE_IPV6) { + return handleNdp(context, ethPkt); + } + return false; + } + + private boolean handleArp(PacketContext context, Ethernet ethPkt) { + ARP arp = (ARP) ethPkt.getPayload(); + + if (arp.getOpCode() == ARP.OP_REPLY) { + forward(ethPkt, context.inPacket().receivedFrom()); + } else if (arp.getOpCode() == ARP.OP_REQUEST) { + reply(ethPkt, context.inPacket().receivedFrom()); + } else { + return false; + } + context.block(); + return true; + } + + private boolean handleNdp(PacketContext context, Ethernet ethPkt) { + IPv6 ipv6 = (IPv6) ethPkt.getPayload(); + + if (ipv6.getNextHeader() != IPv6.PROTOCOL_ICMP6) { + return false; + } + ICMP6 icmpv6 = (ICMP6) ipv6.getPayload(); + if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_ADVERTISEMENT) { + forward(ethPkt, context.inPacket().receivedFrom()); + } else if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_SOLICITATION) { + reply(ethPkt, context.inPacket().receivedFrom()); + } else { + return false; + } + context.block(); + return true; + } + + /** + * Flood the arp request at all edges in the network. + * + * @param request the arp request + * @param inPort the connect point the arp request was received on + */ + private void flood(Ethernet request, ConnectPoint inPort) { + TrafficTreatment.Builder builder = null; + ByteBuffer buf = ByteBuffer.wrap(request.serialize()); + + for (ConnectPoint connectPoint : edgeService.getEdgePoints()) { + if (hasIpAddress(connectPoint) || connectPoint.equals(inPort)) { + continue; + } + + builder = DefaultTrafficTreatment.builder(); + builder.setOutput(connectPoint.port()); + packetService.emit(new DefaultOutboundPacket(connectPoint.deviceId(), + builder.build(), buf)); + } + } + + /** + * Builds an Neighbor Discovery reply based on a request. + * + * @param srcIp the IP address to use as the reply source + * @param srcMac the MAC address to use as the reply source + * @param request the Neighbor Solicitation request we got + * @return an Ethernet frame containing the Neighbor Advertisement reply + */ + private Ethernet buildNdpReply(Ip6Address srcIp, MacAddress srcMac, + Ethernet request) { + Ethernet eth = new Ethernet(); + eth.setDestinationMACAddress(request.getSourceMAC()); + eth.setSourceMACAddress(srcMac); + eth.setEtherType(Ethernet.TYPE_IPV6); + eth.setVlanID(request.getVlanID()); + + IPv6 requestIp = (IPv6) request.getPayload(); + IPv6 ipv6 = new IPv6(); + ipv6.setSourceAddress(srcIp.toOctets()); + ipv6.setDestinationAddress(requestIp.getSourceAddress()); + ipv6.setHopLimit((byte) 255); + + ICMP6 icmp6 = new ICMP6(); + icmp6.setIcmpType(ICMP6.NEIGHBOR_ADVERTISEMENT); + icmp6.setIcmpCode((byte) 0); + + NeighborAdvertisement nadv = new NeighborAdvertisement(); + nadv.setTargetAddress(srcIp.toOctets()); + nadv.setSolicitedFlag((byte) 1); + nadv.setOverrideFlag((byte) 1); + nadv.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, + srcMac.toBytes()); + + icmp6.setPayload(nadv); + ipv6.setPayload(icmp6); + eth.setPayload(ipv6); + return eth; + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/proxyarp/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/proxyarp/impl/package-info.java new file mode 100644 index 00000000..9ce268fb --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/proxyarp/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Core subsystem for responding to arp requests. + */ +package org.onosproject.net.proxyarp.impl; diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/DeviceResourceManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/DeviceResourceManager.java new file mode 100644 index 00000000..62b4112b --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/DeviceResourceManager.java @@ -0,0 +1,104 @@ +/* + * 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.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.Port; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentId; +import org.onosproject.net.resource.device.DeviceResourceService; +import org.onosproject.net.resource.device.DeviceResourceStore; +import org.slf4j.Logger; + +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Provides basic implementation of device resources allocation. + */ +@Component(immediate = true) +@Service +public class DeviceResourceManager implements DeviceResourceService { + + private final Logger log = getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + private DeviceResourceStore store; + + @Activate + public void activate() { + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + + @Override + public boolean requestPorts(Set ports, Intent intent) { + checkNotNull(intent); + + return store.allocatePorts(ports, intent.id()); + } + + @Override + public Set getAllocations(IntentId intentId) { + return store.getAllocations(intentId); + } + + @Override + public IntentId getAllocations(Port port) { + return store.getAllocations(port); + } + + @Override + public void releaseMapping(IntentId intentId) { + store.releaseMapping(intentId); + } + + @Override + public boolean requestMapping(IntentId keyIntentId, IntentId valIntentId) { + return store.allocateMapping(keyIntentId, valIntentId); + } + + @Override + public Set getMapping(IntentId intentId) { + return store.getMapping(intentId); + } + + @Override + public void releasePorts(IntentId intentId) { + store.releasePorts(intentId); + } + + private Port getTypedPort(Set ports, Port.Type type) { + for (Port port : ports) { + if (port.type() == type) { + return port; + } + } + + return null; + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java new file mode 100644 index 00000000..8b9952ed --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java @@ -0,0 +1,293 @@ +/* + * Copyright 2014-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.impl; + +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; +import org.apache.felix.scr.annotations.Reference; +import org.apache.felix.scr.annotations.ReferenceCardinality; +import org.apache.felix.scr.annotations.Service; +import org.onosproject.event.AbstractListenerManager; +import org.onosproject.net.Link; +import org.onosproject.net.intent.IntentId; +import org.onosproject.net.resource.ResourceAllocation; +import org.onosproject.net.resource.ResourceRequest; +import org.onosproject.net.resource.ResourceType; +import org.onosproject.net.resource.link.BandwidthResourceAllocation; +import org.onosproject.net.resource.link.BandwidthResourceRequest; +import org.onosproject.net.resource.link.DefaultLinkResourceAllocations; +import org.onosproject.net.resource.link.LambdaResource; +import org.onosproject.net.resource.link.LambdaResourceAllocation; +import org.onosproject.net.resource.link.LambdaResourceRequest; +import org.onosproject.net.resource.link.LinkResourceAllocations; +import org.onosproject.net.resource.link.LinkResourceEvent; +import org.onosproject.net.resource.link.LinkResourceListener; +import org.onosproject.net.resource.link.LinkResourceRequest; +import org.onosproject.net.resource.link.LinkResourceService; +import org.onosproject.net.resource.link.LinkResourceStore; +import org.onosproject.net.resource.link.LinkResourceStoreDelegate; +import org.onosproject.net.resource.link.MplsLabel; +import org.onosproject.net.resource.link.MplsLabelResourceAllocation; +import org.onosproject.net.resource.link.MplsLabelResourceRequest; +import org.slf4j.Logger; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkArgument; +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 basic implementation of link resources allocation. + */ +@Component(immediate = true) +@Service +public class LinkResourceManager + extends AbstractListenerManager + implements LinkResourceService { + + private final Logger log = getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + private LinkResourceStore store; + + @Activate + public void activate() { + eventDispatcher.addSink(LinkResourceEvent.class, listenerRegistry); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + eventDispatcher.removeSink(LinkResourceEvent.class); + log.info("Stopped"); + } + + /** + * Returns available lambdas on specified link. + * + * @param link the link + * @return available lambdas on specified link + */ + private Set getAvailableLambdas(Link link) { + checkNotNull(link); + Set resAllocs = store.getFreeResources(link); + if (resAllocs == null) { + return Collections.emptySet(); + } + Set lambdas = new HashSet<>(); + for (ResourceAllocation res : resAllocs) { + if (res.type() == ResourceType.LAMBDA) { + lambdas.add(((LambdaResourceAllocation) res).lambda()); + } + } + return lambdas; + } + + + /** + * Returns available lambdas on specified links. + * + * @param links the links + * @return available lambdas on specified links + */ + private Iterable getAvailableLambdas(Iterable links) { + checkNotNull(links); + Iterator i = links.iterator(); + checkArgument(i.hasNext()); + Set lambdas = new HashSet<>(getAvailableLambdas(i.next())); + while (i.hasNext()) { + lambdas.retainAll(getAvailableLambdas(i.next())); + } + return lambdas; + } + + + /** + * Returns available MPLS label on specified link. + * + * @param link the link + * @return available MPLS labels on specified link + */ + private Iterable getAvailableMplsLabels(Link link) { + Set resAllocs = store.getFreeResources(link); + if (resAllocs == null) { + return Collections.emptySet(); + } + Set mplsLabels = new HashSet<>(); + for (ResourceAllocation res : resAllocs) { + if (res.type() == ResourceType.MPLS_LABEL) { + + mplsLabels.add(((MplsLabelResourceAllocation) res).mplsLabel()); + } + } + + return mplsLabels; + } + + @Override + public LinkResourceAllocations requestResources(LinkResourceRequest req) { + checkPermission(LINK_WRITE); + + // TODO Concatenate multiple bandwidth requests. + // TODO Support multiple lambda resource requests. + // TODO Throw appropriate exception. + Set allocs = new HashSet<>(); + Map> allocsPerLink = new HashMap<>(); + for (ResourceRequest r : req.resources()) { + switch (r.type()) { + case BANDWIDTH: + BandwidthResourceRequest br = (BandwidthResourceRequest) r; + allocs.add(new BandwidthResourceAllocation(br.bandwidth())); + break; + case LAMBDA: + Iterator lambdaIterator = + getAvailableLambdas(req.links()).iterator(); + if (lambdaIterator.hasNext()) { + allocs.add(new LambdaResourceAllocation(lambdaIterator.next())); + } else { + log.info("Failed to allocate lambda resource."); + return null; + } + break; + case MPLS_LABEL: + for (Link link : req.links()) { + if (allocsPerLink.get(link) == null) { + allocsPerLink.put(link, new HashSet<>()); + } + Iterator mplsIter = getAvailableMplsLabels(link) + .iterator(); + if (mplsIter.hasNext()) { + allocsPerLink.get(link) + .add(new MplsLabelResourceAllocation(mplsIter + .next())); + } else { + log.info("Failed to allocate MPLS resource."); + break; + } + } + break; + default: + break; + } + } + + Map> allocations = new HashMap<>(); + for (Link link : req.links()) { + allocations.put(link, new HashSet<>(allocs)); + Set linkAllocs = allocsPerLink.get(link); + if (linkAllocs != null) { + allocations.get(link).addAll(linkAllocs); + } + } + LinkResourceAllocations result = + new DefaultLinkResourceAllocations(req, allocations); + store.allocateResources(result); + return result; + + } + + @Override + public void releaseResources(LinkResourceAllocations allocations) { + checkPermission(LINK_WRITE); + final LinkResourceEvent event = store.releaseResources(allocations); + if (event != null) { + post(event); + } + } + + @Override + public LinkResourceAllocations updateResources(LinkResourceRequest req, + LinkResourceAllocations oldAllocations) { + checkPermission(LINK_WRITE); + releaseResources(oldAllocations); + return requestResources(req); + } + + @Override + public Iterable getAllocations() { + checkPermission(LINK_READ); + return store.getAllocations(); + } + + @Override + public Iterable getAllocations(Link link) { + checkPermission(LINK_READ); + return store.getAllocations(link); + } + + @Override + public LinkResourceAllocations getAllocations(IntentId intentId) { + checkPermission(LINK_READ); + return store.getAllocations(intentId); + } + + @Override + public Iterable getAvailableResources(Link link) { + checkPermission(LINK_READ); + + Set freeRes = store.getFreeResources(link); + Set result = new HashSet<>(); + for (ResourceAllocation alloc : freeRes) { + switch (alloc.type()) { + case BANDWIDTH: + result.add(new BandwidthResourceRequest( + ((BandwidthResourceAllocation) alloc).bandwidth())); + break; + case LAMBDA: + result.add(new LambdaResourceRequest()); + break; + case MPLS_LABEL: + result.add(new MplsLabelResourceRequest()); + break; + default: + break; + } + } + return result; + } + + @Override + public Iterable getAvailableResources(Link link, + LinkResourceAllocations allocations) { + checkPermission(LINK_READ); + + Set allocatedRes = allocations.getResourceAllocation(link); + Set result = Sets.newHashSet(getAvailableResources(link)); + result.removeAll(allocatedRes); + return result; + } + + /** + * Store delegate to re-post events emitted from the store. + */ + private class InternalStoreDelegate implements LinkResourceStoreDelegate { + @Override + public void notify(LinkResourceEvent event) { + post(event); + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/package-info.java new file mode 100644 index 00000000..fd0bbdec --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/resource/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Services for reserving network resources, e.g. bandwidth, lambdas. + */ +package org.onosproject.net.resource.impl; diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/StatisticManager.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/StatisticManager.java new file mode 100644 index 00000000..996ad14e --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/StatisticManager.java @@ -0,0 +1,379 @@ +/* + * Copyright 2014 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.FluentIterable; +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.core.ApplicationId; +import org.onosproject.core.GroupId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.Link; +import org.onosproject.net.Path; + +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.statistic.DefaultLoad; +import org.onosproject.net.statistic.Load; +import org.onosproject.net.statistic.StatisticService; +import org.onosproject.net.statistic.StatisticStore; +import org.slf4j.Logger; + +import java.util.Collections; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.slf4j.LoggerFactory.getLogger; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.onosproject.security.AppPermission.Type.*; + + +/** + * Provides an implementation of the Statistic Service. + */ +@Component(immediate = true) +@Service +public class StatisticManager implements StatisticService { + + private final Logger log = getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected FlowRuleService flowRuleService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected StatisticStore statisticStore; + + + private final InternalFlowRuleListener listener = new InternalFlowRuleListener(); + + @Activate + public void activate() { + flowRuleService.addListener(listener); + log.info("Started"); + + } + + @Deactivate + public void deactivate() { + flowRuleService.removeListener(listener); + log.info("Stopped"); + } + + @Override + public Load load(Link link) { + checkPermission(STATISTIC_READ); + + return load(link.src()); + } + + @Override + public Load load(Link link, ApplicationId appId, Optional groupId) { + checkPermission(STATISTIC_READ); + + Statistics stats = getStatistics(link.src()); + if (!stats.isValid()) { + return new DefaultLoad(); + } + + ImmutableSet current = FluentIterable.from(stats.current()) + .filter(hasApplicationId(appId)) + .filter(hasGroupId(groupId)) + .toSet(); + ImmutableSet previous = FluentIterable.from(stats.previous()) + .filter(hasApplicationId(appId)) + .filter(hasGroupId(groupId)) + .toSet(); + + return new DefaultLoad(aggregate(current), aggregate(previous)); + } + + @Override + public Load load(ConnectPoint connectPoint) { + checkPermission(STATISTIC_READ); + + return loadInternal(connectPoint); + } + + @Override + public Link max(Path path) { + checkPermission(STATISTIC_READ); + + if (path.links().isEmpty()) { + return null; + } + Load maxLoad = new DefaultLoad(); + Link maxLink = null; + for (Link link : path.links()) { + Load load = loadInternal(link.src()); + if (load.rate() > maxLoad.rate()) { + maxLoad = load; + maxLink = link; + } + } + return maxLink; + } + + @Override + public Link min(Path path) { + checkPermission(STATISTIC_READ); + + if (path.links().isEmpty()) { + return null; + } + Load minLoad = new DefaultLoad(); + Link minLink = null; + for (Link link : path.links()) { + Load load = loadInternal(link.src()); + if (load.rate() < minLoad.rate()) { + minLoad = load; + minLink = link; + } + } + return minLink; + } + + @Override + public FlowRule highestHitter(ConnectPoint connectPoint) { + checkPermission(STATISTIC_READ); + + Set hitters = statisticStore.getCurrentStatistic(connectPoint); + if (hitters.isEmpty()) { + return null; + } + + FlowEntry max = hitters.iterator().next(); + for (FlowEntry entry : hitters) { + if (entry.bytes() > max.bytes()) { + max = entry; + } + } + return max; + } + + private Load loadInternal(ConnectPoint connectPoint) { + Statistics stats = getStatistics(connectPoint); + if (!stats.isValid()) { + return new DefaultLoad(); + } + + return new DefaultLoad(aggregate(stats.current), aggregate(stats.previous)); + } + + /** + * Returns statistics of the specified port. + * + * @param connectPoint port to query + * @return statistics + */ + private Statistics getStatistics(ConnectPoint connectPoint) { + Set current; + Set previous; + synchronized (statisticStore) { + current = getCurrentStatistic(connectPoint); + previous = getPreviousStatistic(connectPoint); + } + + return new Statistics(current, previous); + } + + /** + * Returns the current statistic of the specified port. + + * @param connectPoint port to query + * @return set of flow entries + */ + private Set getCurrentStatistic(ConnectPoint connectPoint) { + Set stats = statisticStore.getCurrentStatistic(connectPoint); + if (stats == null) { + return Collections.emptySet(); + } else { + return stats; + } + } + + /** + * Returns the previous statistic of the specified port. + * + * @param connectPoint port to query + * @return set of flow entries + */ + private Set getPreviousStatistic(ConnectPoint connectPoint) { + Set stats = statisticStore.getPreviousStatistic(connectPoint); + if (stats == null) { + return Collections.emptySet(); + } else { + return stats; + } + } + + // TODO: make aggregation function generic by passing a function + // (applying Java 8 Stream API?) + /** + * Aggregates a set of values. + * @param values the values to aggregate + * @return a long value + */ + private long aggregate(Set values) { + long sum = 0; + for (FlowEntry f : values) { + sum += f.bytes(); + } + return sum; + } + + /** + * Internal flow rule event listener. + */ + private class InternalFlowRuleListener implements FlowRuleListener { + + @Override + public void event(FlowRuleEvent event) { + FlowRule rule = event.subject(); + switch (event.type()) { + case RULE_ADDED: + case RULE_UPDATED: + if (rule instanceof FlowEntry) { + statisticStore.addOrUpdateStatistic((FlowEntry) rule); + } + break; + case RULE_ADD_REQUESTED: + statisticStore.prepareForStatistics(rule); + break; + case RULE_REMOVE_REQUESTED: + statisticStore.removeFromStatistics(rule); + break; + case RULE_REMOVED: + break; + default: + log.warn("Unknown flow rule event {}", event); + } + } + } + + /** + * Internal data class holding two set of flow entries. + */ + private static class Statistics { + private final ImmutableSet current; + private final ImmutableSet previous; + + public Statistics(Set current, Set previous) { + this.current = ImmutableSet.copyOf(checkNotNull(current)); + this.previous = ImmutableSet.copyOf(checkNotNull(previous)); + } + + /** + * Returns flow entries as the current value. + * + * @return flow entries as the current value + */ + public ImmutableSet current() { + return current; + } + + /** + * Returns flow entries as the previous value. + * + * @return flow entries as the previous value + */ + public ImmutableSet previous() { + return previous; + } + + /** + * Validates values are not empty. + * + * @return false if either of the sets is empty. Otherwise, true. + */ + public boolean isValid() { + return !(current.isEmpty() || previous.isEmpty()); + } + + @Override + public int hashCode() { + return Objects.hash(current, previous); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Statistics)) { + return false; + } + final Statistics other = (Statistics) obj; + return Objects.equals(this.current, other.current) && Objects.equals(this.previous, other.previous); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("current", current) + .add("previous", previous) + .toString(); + } + } + + /** + * Creates a predicate that checks the application ID of a flow entry is the same as + * the specified application ID. + * + * @param appId application ID to be checked + * @return predicate + */ + private static Predicate hasApplicationId(ApplicationId appId) { + return new Predicate() { + @Override + public boolean apply(FlowEntry flowEntry) { + return flowEntry.appId() == appId.id(); + } + }; + } + + /** + * Create a predicate that checks the group ID of a flow entry is the same as + * the specified group ID. + * + * @param groupId group ID to be checked + * @return predicate + */ + private static Predicate hasGroupId(Optional groupId) { + return new Predicate() { + @Override + public boolean apply(FlowEntry flowEntry) { + if (!groupId.isPresent()) { + return false; + } + // FIXME: The left hand type and right hand type don't match + // FlowEntry.groupId() still returns a short value, not int. + return flowEntry.groupId().equals(groupId.get()); + } + }; + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/package-info.java new file mode 100644 index 00000000..b1c9170a --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/statistic/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Core subsystem for responding to statistical inquiries. + */ +package org.onosproject.net.statistic.impl; diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/DefaultTopologyProvider.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/DefaultTopologyProvider.java new file mode 100644 index 00000000..20a5ad36 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/DefaultTopologyProvider.java @@ -0,0 +1,287 @@ +/* + * Copyright 2014-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.impl; + +import static com.google.common.base.Strings.isNullOrEmpty; +import static java.util.concurrent.Executors.newFixedThreadPool; +import static org.onlab.util.Tools.get; +import static org.onlab.util.Tools.groupedThreads; +import static org.onosproject.core.CoreService.CORE_PROVIDER_ID; +import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED; +import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED; +import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_REMOVED; +import static org.slf4j.LoggerFactory.getLogger; + +import java.util.Collections; +import java.util.Dictionary; +import java.util.List; +import java.util.Timer; +import java.util.concurrent.ExecutorService; + +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; +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.AbstractAccumulator; +import org.onlab.util.Accumulator; +import org.onosproject.cfg.ComponentConfigService; +import org.onosproject.event.Event; +import org.onosproject.net.device.DeviceEvent; +import org.onosproject.net.device.DeviceListener; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.link.LinkEvent; +import org.onosproject.net.link.LinkListener; +import org.onosproject.net.link.LinkService; +import org.onosproject.net.provider.AbstractProvider; +import org.onosproject.net.topology.DefaultGraphDescription; +import org.onosproject.net.topology.GraphDescription; +import org.onosproject.net.topology.TopologyProvider; +import org.onosproject.net.topology.TopologyProviderRegistry; +import org.onosproject.net.topology.TopologyProviderService; +import org.osgi.service.component.ComponentContext; +import org.slf4j.Logger; + +import com.google.common.collect.ImmutableList; + +/** + * Default implementation of a network topology provider that feeds off + * device and link subsystem events to trigger assembly and computation of + * new topology snapshots. + */ +@Component(immediate = true) +@Service +public class DefaultTopologyProvider extends AbstractProvider + implements TopologyProvider { + + private static final int MAX_THREADS = 8; + private static final int DEFAULT_MAX_EVENTS = 1000; + private static final int DEFAULT_MAX_IDLE_MS = 10; + private static final int DEFAULT_MAX_BATCH_MS = 50; + + // FIXME: Replace with a system-wide timer instance; + // TODO: Convert to use HashedWheelTimer or produce a variant of that; then decide which we want to adopt + private static final Timer TIMER = new Timer("onos-topo-event-batching"); + + @Property(name = "maxEvents", intValue = DEFAULT_MAX_EVENTS, + label = "Maximum number of events to accumulate") + private int maxEvents = DEFAULT_MAX_EVENTS; + + @Property(name = "maxIdleMs", intValue = DEFAULT_MAX_IDLE_MS, + label = "Maximum number of millis between events") + private int maxIdleMs = DEFAULT_MAX_IDLE_MS; + + @Property(name = "maxBatchMs", intValue = DEFAULT_MAX_BATCH_MS, + label = "Maximum number of millis for whole batch") + private int maxBatchMs = DEFAULT_MAX_BATCH_MS; + + private final Logger log = getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected TopologyProviderRegistry providerRegistry; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected DeviceService deviceService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected LinkService linkService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ComponentConfigService cfgService; + + private volatile boolean isStarted = false; + + private TopologyProviderService providerService; + private final DeviceListener deviceListener = new InternalDeviceListener(); + private final LinkListener linkListener = new InternalLinkListener(); + + private Accumulator accumulator; + private ExecutorService executor; + + /** + * Creates a provider with the supplier identifier. + */ + public DefaultTopologyProvider() { + super(CORE_PROVIDER_ID); + } + + @Activate + public synchronized void activate(ComponentContext context) { + cfgService.registerProperties(DefaultTopologyProvider.class); + executor = newFixedThreadPool(MAX_THREADS, groupedThreads("onos/topo", "build-%d")); + accumulator = new TopologyChangeAccumulator(); + logConfig("Configured"); + + modified(context); + + providerService = providerRegistry.register(this); + deviceService.addListener(deviceListener); + linkService.addListener(linkListener); + + isStarted = true; + triggerRecompute(); + log.info("Started"); + } + + @Deactivate + public synchronized void deactivate(ComponentContext context) { + cfgService.unregisterProperties(DefaultTopologyProvider.class, false); + isStarted = false; + + deviceService.removeListener(deviceListener); + linkService.removeListener(linkListener); + providerRegistry.unregister(this); + providerService = null; + + executor.shutdownNow(); + executor = null; + + log.info("Stopped"); + } + + @Modified + public void modified(ComponentContext context) { + if (context == null) { + accumulator = new TopologyChangeAccumulator(); + logConfig("Reconfigured"); + return; + } + + Dictionary properties = context.getProperties(); + int newMaxEvents, newMaxBatchMs, newMaxIdleMs; + try { + String s = get(properties, "maxEvents"); + newMaxEvents = isNullOrEmpty(s) ? maxEvents : Integer.parseInt(s.trim()); + + s = get(properties, "maxBatchMs"); + newMaxBatchMs = isNullOrEmpty(s) ? maxBatchMs : Integer.parseInt(s.trim()); + + s = get(properties, "maxIdleMs"); + newMaxIdleMs = isNullOrEmpty(s) ? maxIdleMs : Integer.parseInt(s.trim()); + + } catch (NumberFormatException | ClassCastException e) { + newMaxEvents = DEFAULT_MAX_EVENTS; + newMaxBatchMs = DEFAULT_MAX_BATCH_MS; + newMaxIdleMs = DEFAULT_MAX_IDLE_MS; + } + + if (newMaxEvents != maxEvents || newMaxBatchMs != maxBatchMs || newMaxIdleMs != maxIdleMs) { + maxEvents = newMaxEvents; + maxBatchMs = newMaxBatchMs; + maxIdleMs = newMaxIdleMs; + accumulator = maxEvents > 1 ? new TopologyChangeAccumulator() : null; + logConfig("Reconfigured"); + } + } + + private void logConfig(String prefix) { + log.info("{} with maxEvents = {}; maxBatchMs = {}; maxIdleMs = {}; accumulator={}", + prefix, maxEvents, maxBatchMs, maxIdleMs, accumulator != null); + } + + + @Override + public void triggerRecompute() { + triggerTopologyBuild(Collections.emptyList()); + } + + /** + * Triggers assembly of topology data citing the specified events as the + * reason. + * + * @param reasons events which triggered the topology change + */ + private synchronized void triggerTopologyBuild(List reasons) { + if (executor != null) { + executor.execute(new TopologyBuilderTask(reasons)); + } + } + + // Builds the topology using the latest device and link information + // and citing the specified events as reasons for the change. + private void buildTopology(List reasons) { + if (isStarted) { + GraphDescription desc = + new DefaultGraphDescription(System.nanoTime(), + System.currentTimeMillis(), + deviceService.getAvailableDevices(), + linkService.getActiveLinks()); + providerService.topologyChanged(desc, reasons); + } + } + + private void processEvent(Event event) { + if (accumulator != null) { + accumulator.add(event); + } else { + triggerTopologyBuild(ImmutableList.of(event)); + } + } + + // Callback for device events + private class InternalDeviceListener implements DeviceListener { + @Override + public void event(DeviceEvent event) { + DeviceEvent.Type type = event.type(); + if (type == DEVICE_ADDED || type == DEVICE_REMOVED || + type == DEVICE_AVAILABILITY_CHANGED) { + processEvent(event); + } + } + } + + // Callback for link events + private class InternalLinkListener implements LinkListener { + @Override + public void event(LinkEvent event) { + processEvent(event); + } + } + + // Event accumulator for paced triggering of topology assembly. + private class TopologyChangeAccumulator extends AbstractAccumulator { + TopologyChangeAccumulator() { + super(TIMER, maxEvents, maxBatchMs, maxIdleMs); + } + + @Override + public void processItems(List items) { + triggerTopologyBuild(items); + } + } + + // Task for building topology data in a separate thread. + private class TopologyBuilderTask implements Runnable { + private final List reasons; + + public TopologyBuilderTask(List reasons) { + this.reasons = reasons; + } + + @Override + public void run() { + try { + buildTopology(reasons); + } catch (Exception e) { + log.warn("Unable to compute topology", e); + } + } + } + +} 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 new file mode 100644 index 00000000..a238c7fb --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/PathManager.java @@ -0,0 +1,190 @@ +/* + * Copyright 2014 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.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; +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.ConnectPoint; +import org.onosproject.net.DefaultEdgeLink; +import org.onosproject.net.DefaultPath; +import org.onosproject.net.DeviceId; +import org.onosproject.net.EdgeLink; +import org.onosproject.net.ElementId; +import org.onosproject.net.Host; +import org.onosproject.net.HostId; +import org.onosproject.net.HostLocation; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.PortNumber; +import org.onosproject.net.host.HostService; +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.slf4j.Logger; + +import java.util.List; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.slf4j.LoggerFactory.getLogger; +import static org.onosproject.security.AppGuard.checkPermission; +import static org.onosproject.security.AppPermission.Type.*; + + +/** + * Provides implementation of a path selection service atop the current + * topology and host services. + */ +@Component(immediate = true) +@Service +public class PathManager implements PathService { + + private static final String ELEMENT_ID_NULL = "Element ID cannot be null"; + + private static final ProviderId PID = new ProviderId("core", "org.onosproject.core"); + private static final PortNumber P0 = PortNumber.portNumber(0); + + private static final EdgeLink NOT_HOST = new NotHost(); + + private final Logger log = getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected TopologyService topologyService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected HostService hostService; + + @Activate + public void activate() { + log.info("Started"); + } + + @Deactivate + public void deactivate() { + log.info("Stopped"); + } + + @Override + public Set getPaths(ElementId src, ElementId dst) { + checkPermission(TOPOLOGY_READ); + + return getPaths(src, dst, null); + } + + @Override + public Set getPaths(ElementId src, ElementId dst, LinkWeight weight) { + checkPermission(TOPOLOGY_READ); + + 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 edgeToEdgePaths(srcEdge, dstEdge); + } + + // Otherwise get all paths between the source and destination edge + // devices. + Topology topology = topologyService.currentTopology(); + Set paths = weight == null ? + topologyService.getPaths(topology, srcDevice, dstDevice) : + topologyService.getPaths(topology, srcDevice, dstDevice, weight); + + return edgeToEdgePaths(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. + private EdgeLink getEdgeLink(ElementId elementId, boolean isIngress) { + if (elementId instanceof HostId) { + // Resolve the host, return null. + Host host = hostService.getHost((HostId) elementId); + if (host == null) { + return null; + } + return new DefaultEdgeLink(PID, new ConnectPoint(elementId, P0), + host.location(), isIngress); + } + return NOT_HOST; + } + + // Produces a set of edge-to-edge paths using the set of infrastructure + // paths and the given edge links. + private Set edgeToEdgePaths(EdgeLink srcLink, EdgeLink dstLink) { + Set endToEndPaths = Sets.newHashSetWithExpectedSize(1); + endToEndPaths.add(edgeToEdgePath(srcLink, dstLink, null)); + return endToEndPaths; + } + + // Produces a set of edge-to-edge paths using the set of infrastructure + // paths and the given edge links. + private Set edgeToEdgePaths(EdgeLink srcLink, EdgeLink dstLink, Set paths) { + Set endToEndPaths = Sets.newHashSetWithExpectedSize(paths.size()); + for (Path path : paths) { + endToEndPaths.add(edgeToEdgePath(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); + // Add source and destination edge links only if they are real and + // add the infrastructure path only if it is not null. + if (srcLink != NOT_HOST) { + links.add(srcLink); + } + if (path != null) { + links.addAll(path.links()); + } + if (dstLink != NOT_HOST) { + links.add(dstLink); + } + return new DefaultPath(PID, links, 2); + } + + // 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 { + NotHost() { + super(PID, new ConnectPoint(HostId.NONE, P0), + new HostLocation(DeviceId.NONE, P0, 0L), false); + } + } +} 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 new file mode 100644 index 00000000..04c4f1c1 --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/TopologyManager.java @@ -0,0 +1,215 @@ +/* + * Copyright 2014 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.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.provider.AbstractListenerProviderRegistry; +import org.onosproject.event.Event; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.Path; +import org.onosproject.net.provider.AbstractProviderService; +import org.onosproject.net.topology.ClusterId; +import org.onosproject.net.topology.GraphDescription; +import org.onosproject.net.topology.LinkWeight; +import org.onosproject.net.topology.Topology; +import org.onosproject.net.topology.TopologyCluster; +import org.onosproject.net.topology.TopologyEvent; +import org.onosproject.net.topology.TopologyGraph; +import org.onosproject.net.topology.TopologyListener; +import org.onosproject.net.topology.TopologyProvider; +import org.onosproject.net.topology.TopologyProviderRegistry; +import org.onosproject.net.topology.TopologyProviderService; +import org.onosproject.net.topology.TopologyService; +import org.onosproject.net.topology.TopologyStore; +import org.onosproject.net.topology.TopologyStoreDelegate; +import org.slf4j.Logger; + +import java.util.List; +import java.util.Set; + +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 basic implementation of the topology SB & NB APIs. + */ +@Component(immediate = true) +@Service +public class TopologyManager + extends AbstractListenerProviderRegistry + implements TopologyService, TopologyProviderRegistry { + + public static final String TOPOLOGY_NULL = "Topology cannot be null"; + private static final String DEVICE_ID_NULL = "Device ID cannot be null"; + 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"; + + private final Logger log = getLogger(getClass()); + + private TopologyStoreDelegate delegate = new InternalStoreDelegate(); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected TopologyStore store; + + @Activate + public void activate() { + store.setDelegate(delegate); + eventDispatcher.addSink(TopologyEvent.class, listenerRegistry); + log.info("Started"); + } + + @Deactivate + public void deactivate() { + store.unsetDelegate(delegate); + eventDispatcher.removeSink(TopologyEvent.class); + log.info("Stopped"); + } + + @Override + public Topology currentTopology() { + checkPermission(TOPOLOGY_READ); + return store.currentTopology(); + } + + @Override + public boolean isLatest(Topology topology) { + checkPermission(TOPOLOGY_READ); + checkNotNull(topology, TOPOLOGY_NULL); + return store.isLatest(topology); + } + + @Override + public Set getClusters(Topology topology) { + checkPermission(TOPOLOGY_READ); + checkNotNull(topology, TOPOLOGY_NULL); + return store.getClusters(topology); + } + + @Override + public TopologyCluster getCluster(Topology topology, ClusterId clusterId) { + checkPermission(TOPOLOGY_READ); + checkNotNull(topology, TOPOLOGY_NULL); + checkNotNull(topology, CLUSTER_ID_NULL); + return store.getCluster(topology, clusterId); + } + + @Override + public Set getClusterDevices(Topology topology, TopologyCluster cluster) { + checkPermission(TOPOLOGY_READ); + checkNotNull(topology, TOPOLOGY_NULL); + checkNotNull(topology, CLUSTER_NULL); + return store.getClusterDevices(topology, cluster); + } + + @Override + public Set getClusterLinks(Topology topology, TopologyCluster cluster) { + checkPermission(TOPOLOGY_READ); + checkNotNull(topology, TOPOLOGY_NULL); + checkNotNull(topology, CLUSTER_NULL); + return store.getClusterLinks(topology, cluster); + } + + @Override + public TopologyGraph getGraph(Topology topology) { + checkPermission(TOPOLOGY_READ); + checkNotNull(topology, TOPOLOGY_NULL); + return store.getGraph(topology); + } + + @Override + public Set getPaths(Topology topology, DeviceId src, DeviceId dst) { + checkPermission(TOPOLOGY_READ); + checkNotNull(topology, TOPOLOGY_NULL); + checkNotNull(src, DEVICE_ID_NULL); + checkNotNull(dst, DEVICE_ID_NULL); + return store.getPaths(topology, src, dst); + } + + @Override + public Set getPaths(Topology topology, DeviceId src, DeviceId dst, LinkWeight weight) { + checkPermission(TOPOLOGY_READ); + + checkNotNull(topology, TOPOLOGY_NULL); + checkNotNull(src, DEVICE_ID_NULL); + checkNotNull(dst, DEVICE_ID_NULL); + checkNotNull(weight, "Link weight cannot be null"); + return store.getPaths(topology, src, dst, weight); + } + + @Override + public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) { + checkPermission(TOPOLOGY_READ); + checkNotNull(topology, TOPOLOGY_NULL); + checkNotNull(connectPoint, CONNECTION_POINT_NULL); + return store.isInfrastructure(topology, connectPoint); + } + + @Override + public boolean isBroadcastPoint(Topology topology, ConnectPoint connectPoint) { + checkPermission(TOPOLOGY_READ); + checkNotNull(topology, TOPOLOGY_NULL); + checkNotNull(connectPoint, CONNECTION_POINT_NULL); + return store.isBroadcastPoint(topology, connectPoint); + } + + // Personalized host provider service issued to the supplied provider. + @Override + protected TopologyProviderService createProviderService(TopologyProvider provider) { + return new InternalTopologyProviderService(provider); + } + + private class InternalTopologyProviderService + extends AbstractProviderService + implements TopologyProviderService { + + InternalTopologyProviderService(TopologyProvider provider) { + super(provider); + } + + @Override + public void topologyChanged(GraphDescription topoDescription, + List reasons) { + checkNotNull(topoDescription, "Topology description cannot be null"); + + TopologyEvent event = store.updateTopology(provider().id(), + topoDescription, reasons); + if (event != null) { + log.info("Topology {} changed", event.subject()); + post(event); + } + } + } + + // Store delegate to re-post events emitted from the store. + private class InternalStoreDelegate implements TopologyStoreDelegate { + @Override + public void notify(TopologyEvent event) { + post(event); + } + } +} diff --git a/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/package-info.java b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/package-info.java new file mode 100644 index 00000000..586bbf3b --- /dev/null +++ b/framework/src/onos/core/net/src/main/java/org/onosproject/net/topology/impl/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2014 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. + */ + +/** + * Core subsystem for tracking global & consistent topology graph views. + */ +package org.onosproject.net.topology.impl; diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java b/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java new file mode 100644 index 00000000..1ce31ac3 --- /dev/null +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/ApplicationManagerTest.java @@ -0,0 +1,198 @@ +/* + * 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.app.impl; + +import com.google.common.collect.ImmutableSet; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.app.ApplicationEvent; +import org.onosproject.app.ApplicationListener; +import org.onosproject.app.ApplicationState; +import org.onosproject.app.ApplicationStoreAdapter; +import org.onosproject.common.app.ApplicationArchive; +import org.onosproject.core.Application; +import org.onosproject.core.ApplicationId; +import org.onosproject.core.DefaultApplication; +import org.onosproject.core.DefaultApplicationId; +import org.onosproject.common.event.impl.TestEventDispatcher; + +import java.io.InputStream; +import java.net.URI; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.onosproject.app.ApplicationEvent.Type.*; +import static org.onosproject.app.ApplicationState.ACTIVE; +import static org.onosproject.app.ApplicationState.INSTALLED; +import static org.onosproject.app.DefaultApplicationDescriptionTest.*; +import static org.onosproject.net.NetTestTools.injectEventDispatcher; + +/** + * Test of the application manager implementation. + */ +public class ApplicationManagerTest { + + public static final DefaultApplicationId APP_ID = new DefaultApplicationId(1, APP_NAME); + + private ApplicationManager mgr = new ApplicationManager(); + private ApplicationListener listener = new TestListener(); + + @Before + public void setUp() { + injectEventDispatcher(mgr, new TestEventDispatcher()); + mgr.featuresService = new TestFeaturesService(); + mgr.store = new TestStore(); + mgr.activate(); + mgr.addListener(listener); + } + + @After + public void tearDown() { + mgr.removeListener(listener); + mgr.deactivate(); + } + + private void validate(Application app) { + assertEquals("incorrect name", APP_NAME, app.id().name()); + assertEquals("incorrect version", VER, app.version()); + assertEquals("incorrect origin", ORIGIN, app.origin()); + + assertEquals("incorrect description", DESC, app.description()); + assertEquals("incorrect features URI", FURL, app.featuresRepo().get()); + assertEquals("incorrect features", FEATURES, app.features()); + } + + @Test + public void install() { + InputStream stream = ApplicationArchive.class.getResourceAsStream("app.zip"); + Application app = mgr.install(stream); + validate(app); + assertEquals("incorrect features URI used", app.featuresRepo().get(), + ((TestFeaturesService) mgr.featuresService).uri); + assertEquals("incorrect app count", 1, mgr.getApplications().size()); + assertEquals("incorrect app", app, mgr.getApplication(APP_ID)); + assertEquals("incorrect app state", INSTALLED, mgr.getState(APP_ID)); + } + + @Test + public void uninstall() { + install(); + mgr.uninstall(APP_ID); + assertEquals("incorrect app count", 0, mgr.getApplications().size()); + } + + @Test + public void activate() { + install(); + mgr.activate(APP_ID); + assertEquals("incorrect app state", ACTIVE, mgr.getState(APP_ID)); + } + + @Test + public void deactivate() { + activate(); + mgr.deactivate(APP_ID); + assertEquals("incorrect app state", INSTALLED, mgr.getState(APP_ID)); + } + + + private class TestListener implements ApplicationListener { + private ApplicationEvent event; + + @Override + public void event(ApplicationEvent event) { + this.event = event; + } + } + + private class TestStore extends ApplicationStoreAdapter { + + private Application app; + private ApplicationState state; + + @Override + public Application create(InputStream appDescStream) { + app = new DefaultApplication(APP_ID, VER, DESC, ORIGIN, ROLE, PERMS, + Optional.of(FURL), FEATURES); + state = INSTALLED; + delegate.notify(new ApplicationEvent(APP_INSTALLED, app)); + return app; + } + + @Override + public Set getApplications() { + return app != null ? ImmutableSet.of(app) : ImmutableSet.of(); + } + + @Override + public Application getApplication(ApplicationId appId) { + return app; + } + + @Override + public void remove(ApplicationId appId) { + delegate.notify(new ApplicationEvent(APP_UNINSTALLED, app)); + app = null; + state = null; + } + + @Override + public ApplicationState getState(ApplicationId appId) { + return state; + } + + @Override + public void activate(ApplicationId appId) { + state = ApplicationState.ACTIVE; + delegate.notify(new ApplicationEvent(APP_ACTIVATED, app)); + } + + @Override + public void deactivate(ApplicationId appId) { + state = INSTALLED; + delegate.notify(new ApplicationEvent(APP_DEACTIVATED, app)); + } + } + + private class TestFeaturesService extends FeaturesServiceAdapter { + private URI uri; + private Set features = new HashSet<>(); + + @Override + public void addRepository(URI uri) throws Exception { + this.uri = uri; + } + + @Override + public void removeRepository(URI uri) throws Exception { + this.uri = null; + } + + @Override + public void installFeature(String name) throws Exception { + features.add(name); + } + + @Override + public void uninstallFeature(String name) throws Exception { + features.remove(name); + } + } + +} \ No newline at end of file diff --git a/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/FeaturesServiceAdapter.java b/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/FeaturesServiceAdapter.java new file mode 100644 index 00000000..fc19b0a1 --- /dev/null +++ b/framework/src/onos/core/net/src/test/java/org/onosproject/app/impl/FeaturesServiceAdapter.java @@ -0,0 +1,168 @@ +/* + * 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.app.impl; + +import org.apache.karaf.features.Feature; +import org.apache.karaf.features.Repository; + +import java.net.URI; +import java.util.EnumSet; +import java.util.Set; + +/** + * Adapter for testing against Apache Karaf feature service. + */ +public class FeaturesServiceAdapter implements org.apache.karaf.features.FeaturesService { + @Override + public void validateRepository(URI uri) throws Exception { + + } + + @Override + public void addRepository(URI uri) throws Exception { + + } + + @Override + public void addRepository(URI uri, boolean install) throws Exception { + + } + + @Override + public void removeRepository(URI uri) throws Exception { + + } + + @Override + public void removeRepository(URI uri, boolean uninstall) throws Exception { + + } + + @Override + public void restoreRepository(URI uri) throws Exception { + + } + + @Override + public Repository[] listRepositories() { + return new Repository[0]; + } + + @Override + public Repository getRepository(String repoName) { + return null; + } + + @Override + public Repository getRepository(URI uri) { + return null; + } + + @Override + public String getRepositoryName(URI uri) { + return null; + } + + @Override + public void installFeature(String name) throws Exception { + + } + + @Override + public void installFeature(String name, EnumSet